Uploaded image for project: 'JDK'
  1. JDK
  2. JDK-8205637

JEP 348: Java Compiler Intrinsics for JDK APIs



    • Type: JEP
    • Status: Candidate
    • Priority: P3
    • Resolution: Unresolved
    • Fix Version/s: None
    • Component/s: tools
    • Labels:
    • Author:
      Brian Goetz
    • JEP Type:
    • Exposure:
    • Scope:
    • Discussion:
      amber dash dev at openjdk dot java dot net
    • JEP Number:



      Enable Java compilers to use alternate translation strategies, such as invokedynamic, in order to improve the performance of certain JDK methods designated as compiler intrinsic candidates. Specifically, intrinsify the invocation of String::format and Objects::hash.


      In most cases, the JVM does an excellent job of optimizing bytecode at run time. However, for certain kinds of methods, the Java compiler's standard translation strategy results in bytecode which is hard to optimize. A prime example is String::format, whose signature is:

      public static String format(String formatString, Object... args) { ... }

      The bytecode that javac generates for an invocation of String::format is hard to optimize, despite the best efforts of the JVM's JIT compiler. It is common to have primitive arguments; they must be boxed. A varargs array must be created and initialized with all the arguments. The format string will almost always be a constant string, but it is parsed every time by the implementation of String::format. That implementation is, unsurprisingly, too large to inline. As a result, the bytecode is much slower than we'd like.

      Methods such as String::format and Objects::hash (which has a similar signature) are critically important, since they are concise and reliable ways to implement toString and hashCode. Some developers shy away from using these methods and instead use more verbose and error-prone mechanisms purely out of performance considerations. By optimizing the invocation of String::format and Objects::hash, the most readable and maintainable way to implement toString and hashCode also becomes the most performant way.

      JEP 280 replaced the translation of string concatenation with invokedynamic, resulting in faster bytecode, less allocation churn, and more uniform optimizability. We can apply the same technique to methods such as String::format by compiling invocations of these methods using an alternate translation strategy customizes the bytecode for each specific invocation based information available at compile time, such as the static types and values of the arguments present in the invocation.


      Enable JDK developers to (i) tag methods as candidates for compile-time intrinsification, and (ii) describe appropriate alternate translations of intrinsification candidates that conform to the specification of the candidate method.


      It is not a goal to expose the intrinsification mechanism for use outside of the JDK libraries.


      There are two separate aspects to enabling compile-time intrinsification:

      • Authorizing a Java compiler to select an alternate translation strategy for a given method invocation (that is, a strategy other than JLS 15.12.3); and
      • Implementation in a specific Java compiler to enable specific alternate translation strategies for specific intrinsification candidates.

      The first can be accomplished by creating a Java SE annotation @IntrinsicCandidate which JDK library authors can use to tag suitable methods as candidates for intrinsification. A compiler is thereby authorized to select an alternate, but behavior preserving, translation for invocations of those methods. This specifies only that a compiler may do so, not how a compiler does it. JLS 13.1 would be updated to be aware of this opt-in.

      We propose to accomplish the second in the JDK's javac implementation by creating a mechanism for declaring and registering intrinsic processors. They will be invoked when the compiler encounters an invocation of an intrinsic candidate, and will instruct the compiler as to whether and how to replace the standard translation with an optimized translation. Such intrinsification is entirely optional; a compiler may choose to not intrinsify at all, or may choose to provide command-line options for enabling or disabling intrinsification.

      We intend to intrinsify String::format (and related methods, such as PrintStream::printf) to avoid the boxing overhead, varargs overhead, and repeated analysis of constant format strings. Consider the following invocation of String::format:

      String name = ...
      int age = ...
      String s = String.format("%s: %d", name, age);

      This results in boxing age to an Integer, allocating a varargs array, storing name and the boxed age into the varargs array, and then parsing and interpreting the format string -- on every invocation. When the format string is constant, which it almost always is, the compile-time analysis can select an alternate translation, as follows:

      String s = name + ": " + Integer.toString(age);

      which can be further optimized to an invokedynamic using the mechanics from JEP 280. Note that neither name nor age need to be constant variables in order to select the alternate translation.

      Similarly, invoking Objects::hash has two of the three problems that String::format has: boxing and varargs. The invocation:

      int hashCode() { return Objects.hash(name, age); }

      will similarly box age and then box name and age into a varargs array (which many varargs methods will defensively copy). However, we could instead translate it as follows:

      int hashCode() { return name.hashCode() + 31 * Integer.hashCode(age); }

      which avoids these unnecessary costs.

      Risks and Assumptions

      If not properly implemented, the alternate translation may not be perfectly behaviorally compatible with the specification or original implementation.

      Even if properly implemented, an alternate implementation may not properly track changes made to the original implementation in the future.

      Even if properly implemented and tracked, the maintenance of intrinsic candidate methods and their alternate translations is made more difficult, since changes may need to be made in two places and must be behaviorally identical.


          Issue Links



              • Assignee:
                vromero Vicente Arturo Romero Zaldivar
                briangoetz Brian Goetz
                Vicente Arturo Romero Zaldivar
                Reviewed By:
                Alex Buckley, Brian Goetz, Vicente Arturo Romero Zaldivar
                Endorsed By:
                Alex Buckley
              • Votes:
                0 Vote for this issue
                12 Start watching this issue


                • Created: