JDK-8211062 : Implement bootstrap methods for Formatter related methods
  • Type: Sub-task
  • Component: core-libs
  • Sub-Component: java.lang.invoke
  • Priority: P4
  • Status: Open
  • Resolution: Unresolved
  • OS: generic
  • CPU: generic
  • Submitted: 2018-09-24
  • Updated: 2024-06-20
The Version table provides details related to the release that this issue/RFE will be addressed.

Unresolved : Release in which this issue/RFE will be addressed.
Resolved: Release in which this issue/RFE has been resolved.
Fixed : Release in which this issue/RFE has been fixed. The release containing this fix may be available for download as an Early Access Release or a General Availability Release.

To download the current JDK release, click here.
Other
tbdUnresolved
Related Reports
Relates :  
Description
As part of JDK-8205637 we want to provide invokedynamic based implementations for the following var-args methods:

java.io.PrintStream::printf(String, Object...)
java.io.PrintStream::printf(Locale, String, Object...)
java.io.PrintStream::format(String, Object...)
java.io.PrintStream::format(Locale, String, Object...)

java.io.PrintWriter::printf(String, Object...)
java.io.PrintWriter::printf(Locale, String, Object...)
java.io.PrintWriter::format(String, Object...)
java.io.PrintWriter::format(Locale, String, Object...)

java.lang.String::format(Object..)
java.lang.String::format(Locale, Object...)
java.lang.String::format(String, Object..)
java.lang.String::format(Locale, String, Object...)

java.util.Formatter::format(String, Object...)
java.util.Formatter::format(Locale, String, Object...)

The intention is to base the invokedynamic implementation on java.util.Formatter, but use simpler, optimized 
code where the format string and argument type allows it.

We have a fully working prototype for this feature. There are two implementations, one more directly replicating and leveraging the existing Formatter code, the other based on [java.lang.invoke.StringConcatFactory](https://docs.oracle.com/javase/10/docs/api/java/lang/invoke/StringConcatFactory.html). It is possible to implement all above methods on top of both implementation, although the former implementation is easier to fit to the methods with a pre-existing Appendable (as in all methods above except the String methods), whil the latter is a better fit for the String methods and requires jumping through some hoops for the other methods in the list. 

On the other hand, the StringConcatFactory based implementation allows some further optimization since it pre-renders all parts and is therefore able to calculate the exact length of the formatted string. 

However, there is one case where the StringConcatFactory based method exposes slightly different behaviour from normal Formatter code, and that is when an exception occurs during the formatting. With java.util.Formatter, the parts that have been rendered up until the exception occurred are appended to the formatter's Appendable. With the StringConcatFactory, an exception in any part of the formatting will result in no output at all. Note that this is only true for the non-String methods, since output from a String method throwing an exception will not be visible to the caller.

Because of the issues explained above, a viable approach might be to use the StringConcatFactory based implementation only for String methods, and use the Appendable based implementation for the rest of the supported methods. 

We want to make a few changes to java.util.Formatter to make it more easy to support its use from indy bootstrap. Specifically, we need a method to compile a format string into a list of static strings and formatter tokens. However, since providing this functionality to users of the JDK is not a goal of JDK-8205637, there is no use in exposing that new functionality as part of the public java.util.Formatter API. Instead, we plan to implement the new features using non-public APIs. 

For testing, we need to make sure all tests are run in all possible implementations. This can be done by the following steps:

 - running tests with the compiler and runtime options (for the current prototype this is JTREG="OPTIONS=-javacoption:-XDdoIntrinsics")
 - adding helper code to explicitly exercise test code in all configurations
 - adding specific tests for Formatter intrinsic bootstrap code
 
 
Comments
I've added some preliminary microbenchmark results and the JMH code used to obtain them (see attachments). The results will be updated as the code evolves. The results were obtained with the following configurations: - Fallback: indy callsite that mimics traditional bytecode by linking to the varargs String.format method - StringBuilder: indy callsite composed using method handles from the Formatter and StringBuilder classes - StringConcatFactory: indy callsite composed using java.lang.invoke.StringConcatFactory in combination with preformatting of arguments Both the StringBuilder and StringConcatFactory results can optimize some conversion/argument/option combinations to avoid overhead such as instantiation of Formatter and/or StringBuilder, retrieval of default Locale. These optimizations allow for a huge speed increase. However, some of these need to be guarded against special cases. For instance, String.format("%d", 3) can be optimized this way for most Locales, however it needs to use Unicode digits if the default Locale (which can be changed at runtime) requires it. Note that the tests include a single-shot benchmark that measures duration of the initial invocation, which includes bootstrapping for indy callsites. This is quite slow for the StringConcatFactory based implementation, as this implementation requires quite a lot of method handle intermediaries. The Formatter/StringBuilder based indy implementation on the other hand is quite straightforward and ressembles the code that is generated by legacy bytecode. One major restriction is that we only optimize formatter items that have no flags or other options (except for uppercase flag where localization is not required). Adding any flags will cause the handle to switch back to Formatter code.
24-10-2018