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

JEP 295: Ahead-of-Time Compilation

    Details

    • Author:
      Vladimir Kozlov
    • JEP Type:
      Feature
    • Exposure:
      Open
    • Subcomponent:
    • Scope:
      Implementation
    • Discussion:
      hotspot dash compiler dash dev at openjdk dot java dot net
    • Effort:
      M
    • Duration:
      M
    • Alert Status:
       Green
    • JEP Number:
      295

      Description

      Summary

      Compile Java classes to native code prior to launching the virtual machine.

      Goals

      • Improve the start-up time of both small and large Java applications, with at most a limited impact on peak performance.

      • Change the end user's work flow as little as possible.

      Non-Goals

      It is not necessary to provide an explicit, exposed library-like mechanism for saving and loading compiled code.

      Motivation

      JIT compilers are fast, but Java programs can become so large that it takes a long time for the JIT to warm up completely. Infrequently-used Java methods might never be compiled at all, potentially incurring a performance penalty due to repeated interpreted invocations.

      Description

      AOT compilation of any JDK modules, classes, or of user code, is experimental and not supported in JDK 9.

      To use the AOTed java.base module, the user will have to compile the module and copy the resulting AOT library into the JDK installation directory, or specify it on java command line. The usage of AOT-compiled code is otherwise completely transparent to end users.

      AOT compilation is done by a new tool, jaotc:

      jaotc --output libHelloWorld.so HelloWorld.class
      jaotc --output libjava.base.so --module java.base

      It uses Graal as the code-generating backend.

      During JVM startup the AOT initialization code looks for well-known shared libraries in a well-known location, or as specified on the command line with the AOTLibrary flag. If shared libraries are found, these are picked up and used. If no shared libraries are found then AOT will be turned off for this JVM instance.

      java -XX:AOTLibrary=./libHelloWorld.so,./libjava.base.so HelloWorld

      New java AOT flags and jaotc flags are listed in following subsections which also have instructions on how to build and install the AOT library for the java.base module.

      The container format used for AOT-compiled code is shared libraries. The JDK 9 version only supports Linux/x64, where the shared library format is ELF. AOT-compiled code in AOT libraries is treated by JVM as extension of existing CodeCache. When a java class is loaded JVM looks if corresponding AOT-compiled methods exist in loaded AOT libraries and add links to them from java methods descriptors. AOT-compiled code follows the same invocation/deoptimization/unloading rules as normal JIT-compiled code.

      Since class bytecodes can change over time, either through changes to the source code or via class transformation and redefinition, the JVM needs to detect such changes and reject AOT-compiled code if the bytecode doesn't match. This is achieved with class fingerprinting. During AOT compilation a fingerprint for each class is generated and stored in the data section of the shared library. Later, when a class is loaded and AOT-compiled code is found for this class, the fingerprint for the current bytecode is compared to the one stored in the shared library. If there is a mismatch then the AOT code for that particular class is not used.

      The same JDK should be used during AOT compilation and execution. Java version is recorded in AOT libraries and checked during their load. AOT recompilation is required when Java is updated.

      jaotc does not resolve referenced classes which are not system classes or part of compiled classes. They have to be added to class path. Otherwise ClassNotFoundException could be thrown during AOT compilation.

      jaotc --output=libfoo.so --jar foo.jar -J-cp -J./
      jaotc --output=libactivation.so --module java.activation -J--add-module=java.se.ee

      AOT usage

      Use jaotc tool to execute AOT compilation. The tool is part of java installation - same as javac.

      jaotc --output libHelloWorld.so HelloWorld.class 

      Then specify generated AOT library during application execution:

      java -XX:AOTLibrary=./libHelloWorld.so HelloWorld 

      For this release the same java runtime configuration should be used during AOT compilation and execution. For example:

      jaotc -J-XX:+UseParallelGC -J-XX:-UseCompressedOops --output libHelloWorld.so HelloWorld.class 
      java -XX:+UseParallelGC -XX:-UseCompressedOops -XX:AOTLibrary=./libHelloWorld.so HelloWorld 

      It includes the requirement to use the same JDK build variant: product or debug.

      The runtime configuration is recorded in AOT library and verified when the library is loaded during execution. If verification failed this AOT library will not be used and JVM will continue run or exit if flag -XX:+UseAOTStrictLoading is specified.

      During JVM startup the AOT initialization code looks for well-known shared libraries in a well-known location or libraries specified by -XX:AOTLibrary option. If shared libraries are found, these are picked up and used. If no shared libraries can be found, AOT will be turned off for this JVM instance run.

      AOT libraries can be compiled in two modes controlled by --compile-for-tiered flag:

      • Non-tiered AOT compiled code behaves similarly to statically compiled C++ code, in that no profiling information is collected and no JIT recompilations will happen.
      • Tiered AOT compiled code does collect profiling information. The profiling done is the same as the simple profiling done by C1 methods compiled at Tier 2. If AOT methods hit the AOT invocation thresholds then these methods are recompiled by C1 at Tier 3 first in order to gather full profiling information. This is required for C2 JIT recompilations in order to produce optimal code and reach peak application performance.

      The extra step of recompiling code at Tier 3 is necessary since the overhead of full profiling is too high to be used for all methods, especially for methods in a module such as java.base. For user applications it might make sense to allow AOT compilations with Tier 3-equivalent profiling, but this will not be supported for JDK 9.

      The logical compilation mode for java.base is tiered AOT since JIT recompilation of java.base methods is desired to reach peak performance. Only in certain scenarios does a non-tiered AOT compilation make sense. This includes applications which require predictable behavior, when footprint is more important than peak performance, or for systems where dynamic code generation is not allowed. In these cases, AOT compilation needs be done on the entire application and is thus experimental in JDK 9.

      The set of AOT libraries could be generated for different execution environment. JVM knows next well-known names for java.base AOT libraries generated for specific runtime configuration. It will look for them in $JAVA_HOME/lib directory and load the one which correspond to current run-time configuration:

      -XX:-UseCompressedOops -XX:+UseG1GC :       libjava.base.so
      -XX:+UseCompressedOops -XX:+UseG1GC :       libjava.base-coop.so
      -XX:-UseCompressedOops -XX:+UseParallelGC : libjava.base-nong1.so
      -XX:+UseCompressedOops -XX:+UseParallelGC : libjava.base-coop-nong1.so

      JVM also knows AOT libraries names for next java modules but their compilation, installation and usage are experimental:

      jdk.compiler 
      jdk.scripting.nashorn 
      jdk.vm.ci 
      jdk.vm.compiler 

      Steps to generate and use an AOT library for the java.base module

      Compile java.base module using jaotc. It requires big java heap to keep data for all compiled methods (about 50000 methods):

      jaotc -J-XX:+UseCompressedOops -J-XX:+UseG1GC -J-Xmx4g --compile-for-tiered --info --compile-commands java.base-list.txt --output libjava.base-coop.so --module java.base 

      Some methods in java.base cause compilation failure and are excluded by using --compile-comands option:

      cat java.base-list.txt
      
      # jaotc: java.lang.StackOverflowError
      exclude sun.util.resources.LocaleNames.getContents()[[Ljava/lang/Object;
      exclude sun.util.resources.TimeZoneNames.getContents()[[Ljava/lang/Object;
      exclude sun.util.resources.cldr.LocaleNames.getContents()[[Ljava/lang/Object;
      exclude sun.util.resources..*.LocaleNames_.*.getContents\(\)\[\[Ljava/lang/Object;
      exclude sun.util.resources..*.LocaleNames_.*_.*.getContents\(\)\[\[Ljava/lang/Object;
      exclude sun.util.resources..*.TimeZoneNames_.*.getContents\(\)\[\[Ljava/lang/Object;
      exclude sun.util.resources..*.TimeZoneNames_.*_.*.getContents\(\)\[\[Ljava/lang/Object;
      # java.lang.Error: Trampoline must not be defined by the bootstrap classloader
      exclude sun.reflect.misc.Trampoline.<clinit>()V
      exclude sun.reflect.misc.Trampoline.invoke(Ljava/lang/reflect/Method;Ljava/lang/Object;[Ljava/lang/Object;)Ljava/lang/Object;
      # JVM asserts
      exclude com.sun.crypto.provider.AESWrapCipher.engineUnwrap([BLjava/lang/String;I)Ljava/security/Key;
      exclude sun.security.ssl.*
      exclude sun.net.RegisteredDomain.<clinit>()V
      # Huge methods
      exclude jdk.internal.module.SystemModules.descriptors()[Ljava/lang/module/ModuleDescriptor;

      After generating AOT library specify it during application execution using -XX:AOTLibrary option (by default java uses G1 and compressed oops in JDK 9 - you don't need to specify those flags):

      java -XX:AOTLibrary=./libjava.base-coop.so,./libHelloWorld.so HelloWorld 

      Or copy generated AOT library to JDK installation directory (you may need to adjust directory's permissions):

      cp libjava.base-coop.so $JAVA_HOME/lib/ 

      In such case it will be loaded automatically without need to specify on command line:

      java -XX:AOTLibrary=./libHelloWorld.so HelloWorld 

      Consider strip unused symbols from AOT library to reduce library's size.

      New run-time AOT flags

      -XX:+/-UseAOT 

      Use AOT-compiled files. By default it is ON.

      -XX:AOTLibrary=<file> 

      Specify a list of AOT library files. Separate libraries entries with colons (:) or comma (,).

      -XX:+/-PrintAOT 

      Print used AOT klasses and methods.

      Additional diagnostic flag is available (requires to specify -XX:+UnlockDiagnosticVMOptions flag):

      -XX:+/-UseAOTStrictLoading 

      Exit JVM if any of AOT libraries has run-time configuration not matching current run-time settings.

      JVM run-time has following Unified Logging AOT tags integrated with JEP 158: Unified JVM Logging.

      aotclassfingerprint 

      create log in case class's fingerprint does not match fingerprint recorded in AOT library.

      aotclassload 

      create log when corresponding class data is found in AOT library.

      aotclassresolve 

      create log when a request from AOT compiled code to resolve class was successful or not.

      jaotc: The Java Ahead-Of-Time compiler

      jaotc is java static compiler which produces native code for compiled java methods. It uses Graal as the code-generating backend and libelf for generating .so AOT library.

      The tool is part of java installation and can be used the same way as javac.

      jaotc <options> <name or list> 

      Where 'name' is class name or jar file. 'list' is a : separated list of class names, modules, jar files or directories which contain class files.

      The following jaotc options are available:

      --output <file>

      Output file name. Default name is "unnamed.so".

      --class-name <class names>

      List of Java classes to compile

      --jar <jar files>

      List of jar files to compile

      --module <modules>

      List of Java modules to compile

      --directory <dirs>

      List of directories where to search for files to compile

      --search-path <dirs>

      List of directories where to search for specified files

      --compile-commands <file>

      Name of file with compile commands:

      exclude sun.util.resources..*.TimeZoneNames_.*.getContents\(\)\[\[Ljava/lang/Object; 
      exclude sun.security.ssl.* 
      compileOnly java.lang.String.* 

      AOT recognizes two compile commands currently:

      exclude       - exclude compilation of specified methods 
      compileOnly   - compile only specified methods 

      Regular expressions are used to specify classes and methods.

      --compile-for-tiered

      Generated profiling code for tiered compilation. By default profiling code is not generated (could be changed in future).

      --compile-with-assertions

      Generate code with java assertions. By default assertions code is not generated.

      --compile-threads <number>

      Number of compilation threads to be used. Default value is min(16, available_cpus).

      --ignore-errors

      Ignores all exceptions thrown during class loading. By default exit compilation if class loading throws exception.

      --exit-on-error

      Exit on compilation errors. By default failed compilation is skipped and compilation of other methods continues.

      --info 

      Print information about compilation phases

      --verbose 

      Print more details about compilation phases, switch on --info flag

      --debug 

      Print even more details, switch on --info and --verbose flags

      --help

      Print jaotc usage message and flags

      --version

      Print version information

      -J<flag>

      Pass flag directly to the JVM runtime system

      Current AOT limitations

      • AOT initial release in JDK 9 is provided for experimental-only use and is restricted to Linux x64 systems running 64-bit Java with either Parallel or G1 GC.
      • The system must have installed libelf to allow generation of AOT shared libraries (.so) as result of AOT compilation.
      • AOT compilation must be executed on the same system or a system with the same configuration on which AOT code will be used by Java application.
      • The same Java run-time configuration must be used during AOT compilation and execution. For example, the jaotc tool should be run with Parallel GC (using the -J flag) if an application will also use Parallel GC with AOT code. Mismatching run-time configuration may cause application crash during execution.
      • May not compile java code which uses dynamically generated classes and bytecode (lambda expressions, invoke dynamic).

      These limitations may be addressed in future releases.

      Alternatives

      The saving of profiles or compilation decisions has been discussed, but that does nothing to reduce the time actually spent compiling the code. It is possible that saving a very late copy of the low-level IR could be done instead, but that seems no less complex.

      Testing

      New AOT jtreg tests will be developed for testing AOT functionality.

      All existing tests can be run with an AOT-enabled JDK. This is already done as separate nightly testing configurations.

      The other configuration runs all tests on an AOT-enabled JDK with an AOT-compiled java.base module.

      Risks and Assumptions

      It’s possible that the use of pre-compiled code could result in less-than-optimal code being used, resulting in a loss of performance. Performance testing shows that some applications benefit from AOT-compiled code, while others clearly show regressions. Since the AOT feature is an opt-in feature, possible performance regressions with user applications are avoidable. If a user finds that an application starts up more slowly, or doesn't reach the expected peak performance, or crash, they can just switch AOT off with the -XX:-UseAOT flag, or remove any AOT libraries.

      It is recommended that AOT compilation will take place in trusted environments, where the JDK libraries and tools are protected from tampering.

      Dependences

      This project depends on JEP 243: Java-Level JVM Compiler Interface, since the AOT compiler uses Graal as the code-generating backend, which in turn depends on JVMCI.

      The project will merge Graal core into the JDK, and deliver it in Linux/x64 builds.

        Issue Links

          Activity

          Hide
          lbourges Laurent Bourgès added a comment -
          It would be excellent to have it in JDK9 !! Congratulations
          Show
          lbourges Laurent Bourgès added a comment - It would be excellent to have it in JDK9 !! Congratulations
          Hide
          kvn Vladimir Kozlov added a comment - - edited
          John, your changes in "Alternatives" are correct.

          In this release there will be no preinstalled AOT libraries. User have to compile java.base module and copy it into java installation directory or specify it on java command line. I clarified it in Description.
          Show
          kvn Vladimir Kozlov added a comment - - edited John, your changes in "Alternatives" are correct. In this release there will be no preinstalled AOT libraries. User have to compile java.base module and copy it into java installation directory or specify it on java command line. I clarified it in Description.
          Hide
          kvn Vladimir Kozlov added a comment - - edited
          Moving JEP to 'Proposed to Target' for JDK 9.
          We have code and tests ready. And SQE have plan for pre-integration testing after code is reviewed. Note, we have nightly testing of AOT code in staging repository for long time already.
          Show
          kvn Vladimir Kozlov added a comment - - edited Moving JEP to 'Proposed to Target' for JDK 9. We have code and tests ready. And SQE have plan for pre-integration testing after code is reviewed. Note, we have nightly testing of AOT code in staging repository for long time already.
          Hide
          kvn Vladimir Kozlov added a comment -
          FC Extension Request
          Justification: Additional time needed due to code review feedback/updates, and PIT testing.
          Risk Assessment: Low. AOT mostly experimental - only AOT’d java.base on Linux-x64 supported and it's optional.
          Proposed Integration Date: Dec 19, 2016
          Proposed Due Date: Dec 21, 2016

          Remaining work: reviews (webrevs are ready), PIT testing and potential integration blocker bugs fixes.
          Show
          kvn Vladimir Kozlov added a comment - FC Extension Request Justification: Additional time needed due to code review feedback/updates, and PIT testing. Risk Assessment: Low. AOT mostly experimental - only AOT’d java.base on Linux-x64 supported and it's optional. Proposed Integration Date: Dec 19, 2016 Proposed Due Date: Dec 21, 2016 Remaining work: reviews (webrevs are ready), PIT testing and potential integration blocker bugs fixes.
          Hide
          kvn Vladimir Kozlov added a comment -
          We decided to make AOT feature as experimental in JDK 9 without exception. Before we intended to support AOTed java.base module - not any more. I updated document.
          Show
          kvn Vladimir Kozlov added a comment - We decided to make AOT feature as experimental in JDK 9 without exception. Before we intended to support AOTed java.base module - not any more. I updated document.
          Hide
          aph Andrew Haley added a comment - - edited
          I have to grumble that this was announced very late in the OpenJDK release cycle, so late that it didn't allow the other OpenJDK ports time to get the work done before the end of the project. It is an experimental option, so that's not quite so bad. I hope that the jkd9u project will look favourably on the other ports so that AOT can be incorporated into OpenJDK 9.1.
          Show
          aph Andrew Haley added a comment - - edited I have to grumble that this was announced very late in the OpenJDK release cycle, so late that it didn't allow the other OpenJDK ports time to get the work done before the end of the project. It is an experimental option, so that's not quite so bad. I hope that the jkd9u project will look favourably on the other ports so that AOT can be incorporated into OpenJDK 9.1.

            People

            • Assignee:
              kvn Vladimir Kozlov
              Reporter:
              kvn Vladimir Kozlov
              Owner:
              Vladimir Kozlov
              Reviewed By:
              John Rose, Mikael Vidstedt
              Endorsed By:
              John Rose
            • Votes:
              1 Vote for this issue
              Watchers:
              21 Start watching this issue

              Dates

              • Due:
                Created:
                Updated:
                Resolved:
                Integration Due: