Self-introduction:

Hello, I am a Java file. My dream was to enter a world called the JVM, where I was told I could fulfill my value and reach the top of my life.

Javac – Front-end compilation:

This is my first stop in the JVM world to compile a class binary from Java via a Javac tool (or any other form, depending on whether you implement classLoad yourself) as follows:

0. Preparation:

Initialize the plug-in annotation handler.

1. Parse and populate symbol table:

  • Lexical and grammatical analysis. The abstract syntax tree (AST) is constructed by transforming the character stream of the source code into a tag set.

  • Populate the symbol table. Generates symbolic addresses and symbolic information.

    A symbol table is a table consisting of a set of symbol addresses and symbol information. The information registered in the symbol table is used in different stages of compilation. In semantic analysis (the following steps), the content registered in the symbol table will be used for semantic checking and intermediate code generation. In the object code generation stage, the symbol table is the basis for address allocation when the symbol name is assigned.

2. Annotation processing:

  • We can think of the plug-in annotation processor as a set of compiler plug-ins that, when working, allow arbitrary elements in the abstract syntax tree to be read, modified, and added. If these plug-ins make changes to the syntax tree during annotation processing, the compiler will go back to parsing and populating the symbol table and reprocess it until no more modifications have been made to the syntax tree by any plug-in annotation processor, called a round.

  • Implementation: Inherit the AbstractProcessor interface. And implement the process method. For example, Lombok can add getters, setters, and toStrings to the syntax tree during compilation. Follow up on lombok details

3. Analysis and bytecode generation

The first few steps give us a properly structured syntax tree, but there is no guarantee that the semantics of the source program are logical. The main task of semantic analysis is to check the context-related properties of the structurally correct source programs, such as type check, control flow check and data flow check. The common idea explosion problem is the prompt that fails to be triggered in the next two checks

  • Annotation checking: whether variables are declared before they are used, whether the data types between variables and assignments match, and so on

  • Data flow analysis and control flow analysis: checks to see if local variables are assigned before use, if each path to a method returns a value, and if all checked exceptions are handled correctly

  • Title, method of sugar

    • Java stereotypes: Java stereotypes are perfunctory implementations that are implemented at compile time.
    • Auto-boxing, auto-unboxing, and for-each loops: Assign values to some base types and fill comparisons automatically.
    • Conditional compilation: Depending on whether a Boolean constant value is true or false, the compiler will eliminate blocks of code in the branch that are not true.

    The gap can be seen by comparison with the following example:

    • Demo.java
    import java.util.Arrays; import java.util.List; /** * @author wuzhentao */ public class Demo { public static void main(String[] args) { System. The out. Println (" -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- foreach syntactic sugar -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- - "); List<Integer> list = Arrays.asList(1, 2, 3, 4); int sum = 0; for (int i : list) { sum += i; } System.out.println(sum); System. Out. Println (" -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- automatically split open a case using the -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- - "); Integer a = 1; Integer b = 2; Long c = 3L; System.out.println(c == (a + b)); System. The out. Println (" -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- conditional compilation -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- - "); if (true) { System.out.println("yes"); } else { System.out.println("no"); }}}Copy the code
    • Demo. Class (use idea to view the class file, should be in the decomcompiled form, but the class itself is a bytecode file, as follows)
    import java.util.Arrays; import java.util.Iterator; import java.util.List; public class Demo { public Demo() { } public static void main(String[] args) { System. The out. Println (" -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- foreach syntactic sugar -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- - "); List<Integer> list = Arrays.asList(1, 2, 3, 4); int sum = 0; int i; for(Iterator var3 = list.iterator(); var3.hasNext(); sum += i) { i = (Integer)var3.next(); } System.out.println(sum); System. Out. Println (" -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- automatically split open a case using the -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- - "); Integer a = 1; Integer b = 2; Long c = 3L; System.out.println(c == (long)(a + b)); System. The out. Println (" -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- conditional compilation -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- - "); System.out.println("yes"); }}Copy the code
    • Cafebabe is a constant that can be used to create a Java virtual machine.

    • The version number
    • Small version number
    • Constant pool
    • Access tokens
    • Class index
    • Index of the parent class
    • Interface index set
    • Set of field tables
    • Method table collection
    • Property sheet collection

Goalie – Class loader

Now I’ve been trained to be a class body, but to get into the JVM world I need an organization called a classloader

1. Member – class loader composition

  • Grand Master: Starts the class loader
  • Two master: extension class loader
  • Three masters: Application class loaders
  • Helper: A group of helpers formed by inheriting the application classloader (three elders) and then inheriting the helper in turn

2. Help rules – Parents delegate

The organization adopts the form of reporting tasks from one level to another, which is ultimately decided by the elder. Only when the elder indicates that the task cannot be handled, the authority of the next level will be delegated to the person who can handle the task at the highest level. This regulation ensures the uniqueness of classes in the JVM world.

3. How to prove that I am the uniqueness of i-class

  • In the JVM world, I need to be identified by a receiver with my name.

Connect to the backend compiler

The classloader took me into the JVM world, and now I need to figure out how to translate my class body into the machine code of the world and how to improve my skills. Ready-made skills can be roughly divided into the following 1.2. Two kinds

1. Interpreters and just-in-time compilers

  • The function of the interpreter is that when the program needs to be started and executed quickly, the interpreter can first play a role in saving the compilation time and running immediately. The interpreter can also save memory on compilation costs.

  • The compiler can compile code into native code, which can reduce interpreter intermediate losses and achieve higher execution efficiency

    • Hotspot VIRTUAL machine’s just-in-time compilers come in C1(client compiler, stable optimization) and C2(server compiler, aggressive optimization) (1.8 JDK).
  • The way an interpreter is used in conjunction with a compiler

    • Mixed mode: this is also hotspot’s default mode, executed by both the interpreter and the compiler.

    • Explain mode: Only the interpreter executes.

    • Compilation mode: Compilation mode is preferred, but the interpreter still has to step in if compilation is not possible.

  • Targeted optimization – Hierarchical compilation

    • Because just-in-time compilers take time to compile native code, it usually takes longer to compile optimized code; In order to compile more optimized code, the interpreter may have to collect performance monitoring information for the compiler, which also affects the speed at which the execution phase can be interpreted. In order to achieve the best balance between application startup response speed and running efficiency, the HotSpot VIRTUAL machine has added the function of hierarchical compilation to the compilation subsystem. The higher the number of layers, the higher the optimization time and memory consumption, and vice versa. Dynamically changing the number of layers can balance the startup speed of the code and the execution efficiency after several runs.
  • Hot code that triggers compilation :1. Methods that are called multiple times,2. Loop bodies that are executed multiple times.

  • Advantages (corresponding to the ahead of time compiler):

    • Can be guidance to optimize performance analysis: continuously collect performance monitoring information, check the code’s preferences, for example, if a conditional branch one path of execution is particularly frequent, and the other path is less, then you can focus your hot code together, centralized optimization and allocation of better resources (branch prediction, registers, cache, etc.) to it
    • Radical predictive optimization: relative to compile in advance, instantaneous compiling strategies can need not so conservative, if it make some performance monitoring information to support a high probability of correct prediction judgment, but there is no guarantee that absolutely right can have boldly in accordance with the high probable rate hypothesis is optimized, one thousand really go to rare branches, There is no irreparable consequence of falling back to a low-level compiler or even an interpreter
    • Link-time optimization :Class files are loaded into virtual machine memory at runtime and optimized native code is generated in the just-in-time compiler. Because Java object references can be dynamic, only just-in-time compilation allows dynamic reference link optimization.

2. Advance the compiler

Compile the code ahead of time

  • Advantages:
    • The performance cost of just-in-time compilers can be avoided to a certain extent
    • You can cache speed up the level of compilation, which eliminates some of the just-in-time compilation and allows the code to be compiled from startup to completion.

The last

The front-end compilation that converted me from the Java body to the Class body, and the classloader that transported me to the JVM world, combined with the optimization of the back-end compiler, improved my skills. Believe me, I’m one step away from the top of my life; Hey hey think about it a little bit excited.