@@ -1096,7 +1096,7 @@ public CodeTypeElement create(CodeTypeElement clazz) {
10961096 continue ;
10971097 }
10981098
1099- inlined .add (createCacheInlinedField (builder , null , null , cache ));
1099+ inlined .addOptional (createCacheInlinedField (builder , null , null , cache ));
11001100 }
11011101 }
11021102
@@ -1118,8 +1118,7 @@ public CodeTypeElement create(CodeTypeElement clazz) {
11181118 continue ;
11191119 }
11201120
1121- inlined .add (createCacheInlinedField (builder , specialization , specializationState , cache ));
1122-
1121+ inlined .addOptional (createCacheInlinedField (builder , specialization , specializationState , cache ));
11231122 }
11241123 }
11251124
@@ -1254,79 +1253,145 @@ private CodeVariableElement createCacheInlinedField(CodeTreeBuilder init, Specia
12541253 final String fieldName = createLocalCachedInlinedName (specialization , cache );
12551254
12561255 // 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 );
12611257
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 ());
12671262
1263+ CacheExpression sharedCache = lookupSharedCacheKey (cache );
12681264 for (InlineFieldData field : sharedCache .getInlinedNode ().getFields ()) {
12691265 if (field .isState ()) {
12701266 BitSet bitSet = allMultiState .findSet (InlinedNodeState .class , field );
12711267
1272- if (bitSet == null ) {
1268+ if (bitSet == null ) { // bitset in specialized class
12731269 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 ());
12771271 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 ();
12811272
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+ }
12821300 } else {
12831301 if (specializationState != null && specializationState .findSet (InlinedNodeState .class , field ) != null ) {
12841302 throw new AssertionError ("Inlined field in specializationState and regular state at the same time." );
12851303 }
1286- init .startGroup ();
1287- init .startCall (bitSet .getName () + "_" , "subUpdater" );
1304+ b .startGroup ();
1305+ b .startCall (bitSet .getName () + "_" , "subUpdater" );
12881306 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 ();
12931311 }
12941312 } else {
1295-
12961313 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 );
13101335 }
1311- init .end ();
1336+ b .string (updaterFieldName );
1337+ } else {
1338+ b .tree (helper .build ());
13121339 }
13131340
13141341 } else {
1315- init .string (inlinedFieldName );
1342+ b .string (inlinedFieldName );
13161343 }
13171344 }
1345+ }
1346+ b .end ();
1347+ b .end ();
13181348
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 ;
13191370 }
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+ }
13281372
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 ;
13301395 }
13311396
13321397 private String createLocalCachedInlinedName (SpecializationData specialization , CacheExpression cache ) {
@@ -2179,6 +2244,7 @@ private void createCachedFieldsImpl(
21792244 if (inline != null ) {
21802245 Parameter parameter = cache .getParameter ();
21812246 String fieldName = createStaticInlinedCacheName (specialization , cache );
2247+
21822248 ExecutableElement cacheMethod = cache .getInlinedNode ().getMethod ();
21832249 CodeVariableElement cachedField = new CodeVariableElement (modifiers (PRIVATE , STATIC , FINAL ), parameter .getType (), fieldName );
21842250 CodeTreeBuilder builder = cachedField .createInitBuilder ();
@@ -2192,12 +2258,13 @@ private void createCachedFieldsImpl(
21922258 if (generateCachedFields ) {
21932259 BitSet specializationBitSet = findInlinedState (specializationState , field );
21942260 CodeVariableElement updaterField = createStateUpdaterField (specialization , specializationState , field , specializationClassElements );
2261+ BitRange range = specializationBitSet .getStates ().queryRange (StateQuery .create (InlinedNodeState .class , field ));
21952262 String updaterFieldName = updaterField .getName ();
21962263 builder .startCall (updaterFieldName , "subUpdater" );
2197- BitRange range = specializationBitSet .getStates ().queryRange (StateQuery .create (InlinedNodeState .class , field ));
21982264 builder .string (String .valueOf (range .offset ));
21992265 builder .string (String .valueOf (range .length ));
22002266 builder .end ();
2267+
22012268 }
22022269 } else {
22032270 /*
@@ -2263,7 +2330,7 @@ private void createCachedFieldsImpl(
22632330 javadoc .end ();
22642331
22652332 if (generateCachedFields ) {
2266- nodeElements . add ( cachedField );
2333+ nodeConstants . updaterReferences . putIfAbsent ( fieldName , cachedField );
22672334 }
22682335 } else {
22692336 Parameter parameter = cache .getParameter ();
@@ -2349,7 +2416,7 @@ private CodeVariableElement createStateUpdaterField(SpecializationData specializ
23492416 if (var == null ) {
23502417 var = new CodeVariableElement (modifiers (PRIVATE , STATIC , FINAL ), field .getFieldType (), updaterFieldName );
23512418 CodeTreeBuilder b = var .createInitBuilder ();
2352- b .startStaticCall (types (). InlineSupport_StateField , "create" );
2419+ b .startStaticCall (field . getFieldType () , "create" );
23532420 if (nodeType == null ) {
23542421 b .startStaticCall (context .getType (MethodHandles .class ), "lookup" ).end ();
23552422 } else {
@@ -7199,7 +7266,7 @@ private CodeTree createCacheAccess(FrameState frameState, SpecializationData spe
71997266 return initializeCache (frameState , specialization , cache );
72007267 }
72017268 if (cache .getInlinedNode () != null ) {
7202- if (frameState .isInlinedNode ()) {
7269+ if (frameState .isInlinedNode () && needsInlineTarget ( specialization , cache ) ) {
72037270 CodeTreeBuilder builder = CodeTreeBuilder .createBuilder ();
72047271 String cacheFieldName = createLocalCachedInlinedName (specialization , cache );
72057272 builder .string ("this." , cacheFieldName );
0 commit comments