[In-depth understanding of the JIT compiler of the Java virtual machine] 1151 In-depth understanding of the Graal compiler

1. Historical background

1. The Graal virtual machine and Graal compiler are still not commercially available in the laboratory, but they are expected to replace or become the basis for the next generation of HotSpot technology in the future. The Graal compiler was originally designed in the Maxine virtual machine [illustration] as the next-generation compiler of the C1X compiler [illustration], so it is of course written in the Java language.

2. In 2012, the Graal compiler was separated from the Maxine virtual machine project and became an independently developed Java compiler project.

3. The Graal compiler was first added to the official JDK in the form of a Jaotc pre-compilation tool in JDK 9. Starting from JDK 10, the Graal compiler can replace the server-side compiler and become the top-level just-in-time compilation in HotSpot's layered compilation Device. The realization of this alternative just-in-time compiler architecture benefits from the emergence of the HotSpot compiler interface.

4. The early Graal used to be the same as C1 and C2, and the collaboration with HotSpot was tightly coupled, which meant that every time Graal was compiled, the entire HotSpot had to be recompiled. JEP 243: Java-Level JVM Compiler Interface (JVMCI), released in JDK 9, enables Graal to be separated from HotSpot's code.

5. Three functions of JVMCI

A: Respond to HotSpot's compilation request, and distribute the request to the just-in-time compiler implemented by Java

B: Allow the compiler to access data structures related to JIT compilation in HotSpot, including classes, fields, methods and performance monitoring data, etc., and provide a set of abstract representations of these data structures at the Java language level.

C: Provides the Java-side abstract representation of the HotSpot Code Cache, allowing the compiler to deploy the compiled binary machine code.

With the three functions, a just-in-time compiler (not limited to Graal) implemented in Java language outside of the HotSpot virtual machine can be integrated into HotSpot, responding to the top-level compilation request issued by HotSpot, and converting the compiled binary code Deploy to HotSpot's code cache.

6. The emergence of Graal and JVMCI, for readers who are not directly engaged in the development of Java virtual machine and compiler, but are curious about Java virtual machine technology, provide a good way to snoop and try compiler technology. Now we will start based on Graal is here to combat the real-time compilation and code optimization process of the HotSpot virtual machine.

Two, build a compilation and debugging environment

1. In order to reduce the complexity of code management, dependency management, compilation and testing, the Graal team wrote a small tool called mx in Python 2 to automate these things.

2. Install mx first

# git clone https://github.com/graalvm/mx.git
# 倒入环境变量
export PATH = 'pwd'/mx:$PATH

Description

Find a suitable JDK to compile. Considering that the Graal VM project is developed based on OpenJDK 8, and the JVMCI interface will be provided after JDK 9, the Graal team has provided an OpenJDK 8 version with JVMCI function. We can choose this version of JDK 8 to compile . When readers only pay attention to the application of Graal compiler on HotSpot and do not want to involve other aspects of Graal VM, they can directly use JDK 9 and later standard Open/OracleJDK.

The Java heap used in the IDE configuration needs to be modified to 2GB or more to ensure that Graal's compilation and construction in the IDE can proceed smoothly

3. Configure the environment variables corresponding to the java version

export JAVA_HOME=/usr/lib/jvm/oraclejdk1.8.0...

4, is to obtain the Graal compiler code

# git clone https://github.com/graalvm/graal.git
# cd /graal/comiler
# mx build

Three, JVMCI compiler interface

1. The core content of the JVMCI interface is actually

Bytecode, the number of variable slots in the variable table, the maximum depth of the operand stack, and the statistical information collected at the bottom of the layered compilation.

2. Interface

interface JVMCICompiler {
    
}

interface CompliationRequest {
    
}

interface JavaMethod {
    
}

Fourth, the code middle representation

1. The code is inside the compiler

The transformation process of bytecode→ideal graph→optimization→machine code (represented by Mach Node Graph).

2. An ideal graph is a directed graph. Nodes are used to represent elements in the program, such as variables, operators, methods, fields, etc., while edges are used to represent data or control flow.

A: The author uses the blue line (indicated by the dashed line) for data flow, and the red line (indicated by the solid line) for control flow)

B: The ideal graph is essentially a graphical representation that combines the data flow graph and the control flow graph in a certain way, using one edge to represent the data flow and the other edge to represent the control flow.

Insert picture description here

How parameter 0 (denoted as P(0)) and parameter 1 (denoted as P(1)) are sent to the addition operation, and then how is the result sent to the division operation together with the constant 2 (denoted as C(2)) .

3. Elimination of common word expressions
Insert picture description here

Insert picture description here

Insert picture description here

Five, code optimization and generation

1. Each node of an ideal graph has two main operations in common, one is Canonicalisation, and the other is Generation.

2. Standardization refers to how to reduce the scale of the ideal graph, that is, the measures to be taken to optimize the code on the basis of the ideal graph.

3. If an arithmetic sub-expression that can be eliminated is found in the graph, then find the duplicate node, then replace and delete it.

example:

The simple operation of adding two integers has also tried constant folding (if both operands are constant, a constant node is returned directly), arithmetic aggregation (constant child nodes of the aggregation tree, such as (a+ 1)+2 aggregates into a+3), sign merge (the opposite sign sub-nodes of the aggregation tree, for example, directly merge (ab)+b or b+(ab) into a), etc.

4. Graal is not directly converted from the ideal graph to the machine code, but like other compilers, it will first generate a low-level intermediate representation (LIR, an intermediate representation related to the specific machine instruction set), and then the HotSpot unified backend Generate machine code.

For operations involving arithmetic addition, it is done in the emitAdd() method of the ArithmeticLIRGeneratorTool interface

5. Target platforms supported by the Graal compiler

Currently it only provides low-level intermediate representations of the instruction sets of the three target platforms (SPARC, x86-AMD64, ARMv8-AArch64).

6. Normalization is not limited to the local scope of a single opcode. Many optimizations are based on the overall situation. This type of operation is completed in the CanonicalizerPhase class.

Guess you like

Origin blog.csdn.net/qq_40996741/article/details/109173594