UseC1Optimizations
flag.
IRScope
and assign it to _top_scope
.
build_graph
. The nesting level of function calls is tracked.
iterate_bytecodes_for_block
.
This method is also essentially a loop with a big switch table inside. Each iteration of the loop processes one single bytecode instruction of the method being compiled. The switch table identifies which bytecode is being currently processed and invoke a method to handle that specific bytecode. Each "block" is a list of instructions connected by pointers. During the IR construction a stack is used to push and pop constant values that are instruction operands. When the instruction that uses those constants is being created the operands are popped from the stack and used to construct a node representing the instruction.
C1 HIR nodes are described in classes defined in the c1_Instruction.hpp/cpp file. Some simple optimizations, like simplifying shift expressions and local value numbering are performed while constructing the IR. Also, profiling instructions are inserted into the IR when the compilation is in a level that requires profiling.
Interestingly, even C1 bails out compilation if a method body is too large!
closure
pointer points to a LIRGenerator object, which is essentially an object able to iterate over IR blocks.do_root
on instructions that are pinned to the block(?).instr->visit(this)
.
Instr is the instruction being converted, for continuing this tutorial I'll assume it is LogicOp
.
The visit method for each C1 HL IR instruction is constructed with help of the C++ preprocessor;
take a look here to see how the LogicOp class is declared and how the visit method is constructed.
v->do_LogicOp(this)
where v
is a pointer to LIRGenerator
.
Note that this method is in c1_LIRGenerator_x86.cpp
instead of c1_LIRGenerator.cpp
.
During the JVM build time, given the values using the configure the project, the build infrastructure will
use preprocessor macros to include the correct .cpp
file for the target architecture of the
JVM - in this case x86_64.
This method basically extract the information from the HL IR nodes and create LL IR operand nodes,
while doing that the method allocate virtual registers for loading operands and storing results of operations.
The call then is forwarded to logic_op
which is also part of LIRGenerator
.
Bytecodes::_iand
the execution will end up in
LIR_List::logical_and,
which basically construct a Low Level IR binary operator node - LIR_Op2
.
ParseGenerator
object that is able to parse Bytecodes.