<div class="__aliyun_email_body_block"><div  style="font-family: Tahoma, Arial, STHeitiSC-Light, SimSun"><div  style="clear: both;"><span >When we run the format and parse of java.time.DateTimeFormatter using `-XX:+UnlockDiagnosticVMOptions -XX:+PrintInlining`, we can see the following output:</span><div  style="clear: both;"><br ></div><div  style="clear: both;">```</div><div  style="clear: both;">@ 40   j.t.f.DTFB$CompositePrinterParser::format (116 bytes)   inline (hot)</div><div  style="clear: both;">  @ 1   f.l.StringBuilder::length (5 bytes)   inline (hot)</div><div  style="clear: both;">    @ 1   j.l.AbstractStringBuilder::length (5 bytes)   accessor</div><div  style="clear: both;">  @ 48   f.t.f.DTFB$DateTimePrinterParser::format (0 bytes)   failed to inline: virtual call</div><div  style="clear: both;">```</div><div  style="clear: both;"><br ></div><div  style="clear: both;">```</div><div  style="clear: both;">@ 37   j.t.f.DTFB$CompositePrinterParser::parse (135 bytes)   inline (hot)</div><div  style="clear: both;">   @ 114   j.t.f.DTFB$DateTimePrinterParser::parse (0 bytes)   failed to inline: virtual call</div><div  style="clear: both;">```</div><div  style="clear: both;"><br ></div><div  style="clear: both;">As seen in this log, both the DateTimeFormatterBuilder$CompositePrinterParser::format and DateTimeFormatterBuilder$CompositePrinterParser::parse methods are `failed to inline: virtual call`. We can eliminate this inline failure by manually unrolling the loop.</div><div  style="clear: both;">Once manually unrolled, inline optimizations can work, enabling optimizations like TypeProfile to take effect and thus improve performance.</div><div  style="clear: both;">Below is the log output after manually unrolling the loop:</div><div  style="clear: both;"><br ></div><div  style="clear: both;">```</div><div  style="clear: both;">@ 41   j.t.f.DTFB$CompositePrinterParser::format (40 bytes)   inline (hot)</div><div  style="clear: both;">  @ 1   j.l.StringBuilder::length (5 bytes)   inline (hot)</div><div  style="clear: both;">    @ 1   j.l.AbstractStringBuilder::length (5 bytes)   accessor</div><div  style="clear: both;">  @ 22   j.t.f.DateTimePrinterParserFactory$$Lambda/0x00000ff801009df8::format (11 bytes)   inline (hot)   </div><div  style="clear: both;">         callee changed to  j.t.f.DTFB$CompositePrinterParser::format (40 bytes)</div><div  style="clear: both;">             \-> TypeProfile (6212/6212 counts) = j/t/f/DateTimePrinterParserFactory$$Lambda+0x00000ff801009df8</div><div  style="clear: both;">    @ 7   j.t.f.DateTimePrinterParserFactory::lambda$createFormatter$11 (195 bytes)   inline (hot)</div><div  style="clear: both;">      @ 6   j.t.f.DTFB$NumberPrinterParser::format (399 bytes)   failed to inline: hot method too big   </div><div  style="clear: both;">           callee changed to  j.t.f.DateTimePrinterParserFactory::lambda$createFormatter$11 (195 bytes)    </div><div  style="clear: both;">                  \-> TypeProfile (7170/7170 counts) = j/t/f/DTFB$NumberPrinterParser</div><div  style="clear: both;">        @ 20   j.t.f.DTFB$CharLiteralPrinterParser::format (11 bytes)   inline (hot)   </div><div  style="clear: both;">        callee changed to  j.t.f.DateTimePrinterParserFactory::lambda$createFormatter$11 (195 bytes) </div><div  style="clear: both;">           \-> TypeProfile (7170/7170 counts) = j/t/f/DateTimeFormatterBuilder$CharLiteralPrinterParser</div><div  style="clear: both;">```</div><div  style="clear: both;"><br ></div><div  style="clear: both;">```</div><div  style="clear: both;"> @ 37   j.t.f.DTFB$CompositePrinterParser::parse (13 bytes)   inline (hot)</div><div  style="clear: both;">   @ 7   j.t.f.DateTimePrinterParserFactory$$Lambda/0x000000800100a950::parse (11 bytes)   inline (hot)</div><div  style="clear: both;">      callee changed to  j.t.f.DTFB$CompositePrinterParser::parse (13 bytes) </div><div  style="clear: both;">         \-> TypeProfile (130649/130649 counts) = j/t/f/DateTimePrinterParserFactory$$Lambda+0x000000800100a950</div><div  style="clear: both;">     @ 7   j.t.f.DateTimePrinterParserFactory::lambda$createParser$9 (217 bytes)   inline (hot)</div><div  style="clear: both;">       @ 6   j.t.f.DTFB$NumberPrinterParser::parse (609 bytes)   failed to inline: hot method too big</div><div  style="clear: both;">          callee changed to  j.t.f.DateTimePrinterParserFactory::lambda$createParser$9 (217 bytes)</div><div  style="clear: both;">              \-> TypeProfile (130884/130884 counts) = j/t/f/DTFB$NumberPrinterParser</div><div  style="clear: both;">       @ 26   j.t.f.DTFB$CharLiteralPrinterParser::parse (91 bytes)   inline (hot)</div><div  style="clear: both;">          callee changed to  j.t.f.DateTimePrinterParserFactory::lambda$createParser$9 (217 bytes) </div><div  style="clear: both;">          \-> TypeProfile (130884/130884 counts) = j/t/f/DTFB$CharLiteralPrinterParser</div><div  style="clear: both;">```</div><div  style="clear: both;"><br ></div><div  style="clear: both;">We see that the format and parse methods of both NumberPrinterParser and CharLiteralPrinterParser trigger TypeProfile optimization. </div><span >We can choose to generate the code for the unrolling loop based on MethodHandle, the ClassFile API, or Gensrc.gmk. Using MethodHandle or the ClassFile API will make the code obscure and difficult to understand. I recommend using Gensrc.gmk. One advantage of Gensrc.gmk is that the initial performance is better than other implementations.</span></div><div  style="clear: both;"><span ><br ></span></div><div  style="clear: both;"><span ><span >To better express my ideas, I submitted a draft PR: <a  href="https://github.com/openjdk/jdk/pull/28465" target="_blank">https://github.com/openjdk/jdk/pull/28465</a>, and I hope you can give me feedback.</span></span></div><div  style="clear: both;"><span >-</span></div><div  style="clear: both;"><span >Shaojin Wen</span></div></div></div>