@@ -1096,7 +1096,7 @@ public CodeTypeElement create(CodeTypeElement clazz) {
1096
1096
continue ;
1097
1097
}
1098
1098
1099
- inlined .add (createCacheInlinedField (builder , null , null , cache ));
1099
+ inlined .addOptional (createCacheInlinedField (builder , null , null , cache ));
1100
1100
}
1101
1101
}
1102
1102
@@ -1118,8 +1118,7 @@ public CodeTypeElement create(CodeTypeElement clazz) {
1118
1118
continue ;
1119
1119
}
1120
1120
1121
- inlined .add (createCacheInlinedField (builder , specialization , specializationState , cache ));
1122
-
1121
+ inlined .addOptional (createCacheInlinedField (builder , specialization , specializationState , cache ));
1123
1122
}
1124
1123
}
1125
1124
@@ -1254,79 +1253,145 @@ private CodeVariableElement createCacheInlinedField(CodeTreeBuilder init, Specia
1254
1253
final String fieldName = createLocalCachedInlinedName (specialization , cache );
1255
1254
1256
1255
// for state access we need use the shared cache
1257
- CacheExpression sharedCache = lookupSharedCacheKey (cache );
1258
-
1259
- init .startStatement ();
1260
- init .string ("this." , fieldName , " = " );
1256
+ boolean needsInlineTarget = needsInlineTarget (specialization , cache );
1261
1257
1262
- init .startStaticCall (cache .getInlinedNode ().getMethod ());
1263
- init .startStaticCall (types ().InlineSupport_InlineTarget , "create" );
1264
- init .typeLiteral (cache .getParameter ().getType ());
1265
-
1266
- boolean parentAccess = hasCacheParentAccess (cache );
1258
+ CodeTreeBuilder b = init .create ();
1259
+ b .startStaticCall (cache .getInlinedNode ().getMethod ());
1260
+ b .startStaticCall (types ().InlineSupport_InlineTarget , "create" );
1261
+ b .typeLiteral (cache .getParameter ().getType ());
1267
1262
1263
+ CacheExpression sharedCache = lookupSharedCacheKey (cache );
1268
1264
for (InlineFieldData field : sharedCache .getInlinedNode ().getFields ()) {
1269
1265
if (field .isState ()) {
1270
1266
BitSet bitSet = allMultiState .findSet (InlinedNodeState .class , field );
1271
1267
1272
- if (bitSet == null ) {
1268
+ if (bitSet == null ) { // bitset in specialized class
1273
1269
bitSet = findInlinedState (specializationState , field );
1274
-
1275
- CodeVariableElement var = createStateUpdaterField (specialization , specializationState , field , specializationClasses .get (specialization ).getEnclosedElements ());
1276
- init .startCall (var .getName (), "subUpdater" );
1270
+ CodeVariableElement stateVariable = createStateUpdaterField (specialization , specializationState , field , specializationClasses .get (specialization ).getEnclosedElements ());
1277
1271
BitRange range = bitSet .getStates ().queryRange (StateQuery .create (InlinedNodeState .class , field ));
1278
- init .string (String .valueOf (range .offset ));
1279
- init .string (String .valueOf (range .length ));
1280
- init .end ();
1281
1272
1273
+ CodeTreeBuilder helper = b .create ();
1274
+ helper .startCall (stateVariable .getName (), "subUpdater" );
1275
+ helper .string (String .valueOf (range .offset ));
1276
+ helper .string (String .valueOf (range .length ));
1277
+ helper .end ();
1278
+
1279
+ /*
1280
+ * If we need a target to instantiate we should create a constant for the
1281
+ * individual field to avoid unnecessary allocations for each instance.
1282
+ *
1283
+ * If we don't need an inline target, we don't need to extract into a constant
1284
+ * here as the entire cached initializer result will be stored as constant. No
1285
+ * need to create constants for individual fields, which would then be more
1286
+ * costly.
1287
+ */
1288
+ if (needsInlineTarget ) {
1289
+ String updaterFieldName = stateVariable .getSimpleName ().toString () + "_" + range .offset + "_" + range .length ;
1290
+ CodeVariableElement var = nodeConstants .updaterReferences .get (updaterFieldName );
1291
+ if (var == null ) {
1292
+ var = new CodeVariableElement (modifiers (PRIVATE , STATIC , FINAL ), stateVariable .getType (), updaterFieldName );
1293
+ var .createInitBuilder ().tree (helper .build ());
1294
+ nodeConstants .updaterReferences .put (updaterFieldName , var );
1295
+ }
1296
+ b .string (updaterFieldName );
1297
+ } else {
1298
+ b .tree (helper .build ());
1299
+ }
1282
1300
} else {
1283
1301
if (specializationState != null && specializationState .findSet (InlinedNodeState .class , field ) != null ) {
1284
1302
throw new AssertionError ("Inlined field in specializationState and regular state at the same time." );
1285
1303
}
1286
- init .startGroup ();
1287
- init .startCall (bitSet .getName () + "_" , "subUpdater" );
1304
+ b .startGroup ();
1305
+ b .startCall (bitSet .getName () + "_" , "subUpdater" );
1288
1306
BitRange range = bitSet .getStates ().queryRange (StateQuery .create (InlinedNodeState .class , field ));
1289
- init .string (String .valueOf (range .offset ));
1290
- init .string (String .valueOf (range .length ));
1291
- init .end ();
1292
- init .end ();
1307
+ b .string (String .valueOf (range .offset ));
1308
+ b .string (String .valueOf (range .length ));
1309
+ b .end ();
1310
+ b .end ();
1293
1311
}
1294
1312
} else {
1295
-
1296
1313
String inlinedFieldName = createCachedInlinedFieldName (specialization , cache , field );
1297
- if (specialization != null && useSpecializationClass (specialization )) {
1298
- if (parentAccess ) {
1299
- init .startGroup ();
1300
- init .string ("this." , inlinedFieldName );
1301
- init .end ();
1302
- } else {
1303
- init .startStaticCall (field .getFieldType (), "create" );
1304
- init .startGroup ();
1305
- init .tree (createLookupNodeType (createSpecializationClassReferenceType (specialization ), specializationClasses .get (specialization ).getEnclosedElements ()));
1306
- init .end ();
1307
- init .doubleQuote (inlinedFieldName );
1308
- if (field .isReference ()) {
1309
- init .typeLiteral (field .getType ());
1314
+ if (specialization != null && useSpecializationClass (specialization ) && cache .getSharedGroup () == null ) {
1315
+ CodeTypeElement specializationDataClass = specializationClasses .get (specialization );
1316
+ CodeTreeBuilder helper = b .create ();
1317
+
1318
+ helper .startStaticCall (field .getFieldType (), "create" );
1319
+ helper .startGroup ();
1320
+ helper .tree (createLookupNodeType (createSpecializationClassReferenceType (specialization ), specializationDataClass .getEnclosedElements ()));
1321
+ helper .end ();
1322
+ helper .doubleQuote (inlinedFieldName );
1323
+ if (field .isReference ()) {
1324
+ helper .typeLiteral (field .getType ());
1325
+ }
1326
+ helper .end ();
1327
+
1328
+ if (needsInlineTarget ) {
1329
+ String updaterFieldName = ElementUtils .createConstantName (specializationDataClass .getSimpleName ().toString () + "_" + inlinedFieldName ) + "_UPDATER" ;
1330
+ CodeVariableElement var = nodeConstants .updaterReferences .get (updaterFieldName );
1331
+ if (var == null ) {
1332
+ var = new CodeVariableElement (modifiers (PRIVATE , STATIC , FINAL ), field .getFieldType (), updaterFieldName );
1333
+ var .createInitBuilder ().tree (helper .build ());
1334
+ nodeConstants .updaterReferences .put (updaterFieldName , var );
1310
1335
}
1311
- init .end ();
1336
+ b .string (updaterFieldName );
1337
+ } else {
1338
+ b .tree (helper .build ());
1312
1339
}
1313
1340
1314
1341
} else {
1315
- init .string (inlinedFieldName );
1342
+ b .string (inlinedFieldName );
1316
1343
}
1317
1344
}
1345
+ }
1346
+ b .end ();
1347
+ b .end ();
1318
1348
1349
+ // if the initializer does not need the target we can create a constant instead
1350
+ if (needsInlineTarget ) {
1351
+ init .startStatement ();
1352
+ init .string ("this." , fieldName , " = " );
1353
+ init .tree (b .build ());
1354
+ init .end ();
1355
+ CodeVariableElement var = new CodeVariableElement (modifiers (PRIVATE , FINAL ), parameter .getType (), fieldName );
1356
+ CodeTreeBuilder builder = var .createDocBuilder ();
1357
+ builder .startJavadoc ();
1358
+ addSourceDoc (builder , specialization , cache , null );
1359
+ builder .end ();
1360
+ return var ;
1361
+ } else {
1362
+ String name = createStaticInlinedCacheName (specialization , cache );
1363
+ CodeVariableElement var = nodeConstants .updaterReferences .get (name );
1364
+ if (var == null ) {
1365
+ var = new CodeVariableElement (modifiers (PRIVATE , STATIC , FINAL ), parameter .getType (), name );
1366
+ var .createInitBuilder ().tree (b .build ());
1367
+ nodeConstants .updaterReferences .put (name , var );
1368
+ }
1369
+ return null ;
1319
1370
}
1320
- init .end ();
1321
- init .end ();
1322
- init .end ();
1323
- CodeVariableElement var = new CodeVariableElement (modifiers (PRIVATE , FINAL ), parameter .getType (), fieldName );
1324
- CodeTreeBuilder builder = var .createDocBuilder ();
1325
- builder .startJavadoc ();
1326
- addSourceDoc (builder , specialization , cache , null );
1327
- builder .end ();
1371
+ }
1328
1372
1329
- return var ;
1373
+ /**
1374
+ * Returns <code>true</code> if the inlined cache requires any field from the inline target to
1375
+ * get initialized, else <code>false</code>. If it does not depend on the inline target the code
1376
+ * generator can typically extract the instance into a static final field instead of
1377
+ * initializing it in the generated Inlined class constructor.
1378
+ */
1379
+ private boolean needsInlineTarget (SpecializationData specialization , CacheExpression cache ) {
1380
+ if (cache .getSharedGroup () != null ) {
1381
+ // shared cache -> never in data class
1382
+ return true ;
1383
+ }
1384
+ for (InlineFieldData field : cache .getInlinedNode ().getFields ()) {
1385
+ if (field .isState () && allMultiState .findSet (InlinedNodeState .class , field ) == null ) {
1386
+ // bit set located in specialization data class, no access to inline target needed
1387
+ } else if (specialization != null && useSpecializationClass (specialization )) {
1388
+ // we use a data class for this specialization so the field is stored there
1389
+ } else {
1390
+ // by default state is stored in the parent node
1391
+ return true ;
1392
+ }
1393
+ }
1394
+ return false ;
1330
1395
}
1331
1396
1332
1397
private String createLocalCachedInlinedName (SpecializationData specialization , CacheExpression cache ) {
@@ -2179,6 +2244,7 @@ private void createCachedFieldsImpl(
2179
2244
if (inline != null ) {
2180
2245
Parameter parameter = cache .getParameter ();
2181
2246
String fieldName = createStaticInlinedCacheName (specialization , cache );
2247
+
2182
2248
ExecutableElement cacheMethod = cache .getInlinedNode ().getMethod ();
2183
2249
CodeVariableElement cachedField = new CodeVariableElement (modifiers (PRIVATE , STATIC , FINAL ), parameter .getType (), fieldName );
2184
2250
CodeTreeBuilder builder = cachedField .createInitBuilder ();
@@ -2192,12 +2258,13 @@ private void createCachedFieldsImpl(
2192
2258
if (generateCachedFields ) {
2193
2259
BitSet specializationBitSet = findInlinedState (specializationState , field );
2194
2260
CodeVariableElement updaterField = createStateUpdaterField (specialization , specializationState , field , specializationClassElements );
2261
+ BitRange range = specializationBitSet .getStates ().queryRange (StateQuery .create (InlinedNodeState .class , field ));
2195
2262
String updaterFieldName = updaterField .getName ();
2196
2263
builder .startCall (updaterFieldName , "subUpdater" );
2197
- BitRange range = specializationBitSet .getStates ().queryRange (StateQuery .create (InlinedNodeState .class , field ));
2198
2264
builder .string (String .valueOf (range .offset ));
2199
2265
builder .string (String .valueOf (range .length ));
2200
2266
builder .end ();
2267
+
2201
2268
}
2202
2269
} else {
2203
2270
/*
@@ -2263,7 +2330,7 @@ private void createCachedFieldsImpl(
2263
2330
javadoc .end ();
2264
2331
2265
2332
if (generateCachedFields ) {
2266
- nodeElements . add ( cachedField );
2333
+ nodeConstants . updaterReferences . putIfAbsent ( fieldName , cachedField );
2267
2334
}
2268
2335
} else {
2269
2336
Parameter parameter = cache .getParameter ();
@@ -2349,7 +2416,7 @@ private CodeVariableElement createStateUpdaterField(SpecializationData specializ
2349
2416
if (var == null ) {
2350
2417
var = new CodeVariableElement (modifiers (PRIVATE , STATIC , FINAL ), field .getFieldType (), updaterFieldName );
2351
2418
CodeTreeBuilder b = var .createInitBuilder ();
2352
- b .startStaticCall (types (). InlineSupport_StateField , "create" );
2419
+ b .startStaticCall (field . getFieldType () , "create" );
2353
2420
if (nodeType == null ) {
2354
2421
b .startStaticCall (context .getType (MethodHandles .class ), "lookup" ).end ();
2355
2422
} else {
@@ -7199,7 +7266,7 @@ private CodeTree createCacheAccess(FrameState frameState, SpecializationData spe
7199
7266
return initializeCache (frameState , specialization , cache );
7200
7267
}
7201
7268
if (cache .getInlinedNode () != null ) {
7202
- if (frameState .isInlinedNode ()) {
7269
+ if (frameState .isInlinedNode () && needsInlineTarget ( specialization , cache ) ) {
7203
7270
CodeTreeBuilder builder = CodeTreeBuilder .createBuilder ();
7204
7271
String cacheFieldName = createLocalCachedInlinedName (specialization , cache );
7205
7272
builder .string ("this." , cacheFieldName );
0 commit comments