Jikes RVM includes two compilers. One is the baseline
compiler, and the other is optimizing compiler, which is commonly
referred to as the JIT compiler. BaseBase builds run JikesRVM with only the Baseline Compiler, where the other builds such as Production (FastAdaptive), Development (FullAdaptive), and the ExtremeAssertion builds have both the baseline and optimizing compilers.
Here, we will study the optimizing
compiler in Jikes RVM. The package org.jikesrvm.compilers
contains the source code of the compilers, where The package
org.jikesrvm.compilers.opt contains the code of the optimizing
compiler.
SharedBooleanOptions.dat found in the directory
/rvm/src-generated/options defines the boolean options for the
optimizing compiler. Similarly, SharedValueOptions.dat in
the same directory defines the non-boolean options.
1.
Transformations of Methods
Jikes RVM takes methods as the fundamental unit of
optimization, and optimize them by transforming the intermediate
representation as below.
Byte
Code → [Optimizing Compiler] → Machine Code + Mapping
Information
|
Mapping information consists of garbage collection
maps, source code maps, and execution tables. Optimizing
compiler has the following intermediate phase transitions, for the
intermediate representation.
High-level
Intermediate Representation (HIR) → Low-level Intermediate
Representation → Machine Intermediate Representation.
|
The general structure of the master plan consists of
elements,
- Converting, byte codes → HIR, HIR → LIR, LIR → MIR, and MIR → Machine Code.
- Performing optimization transformations on the HIR, LIR, and MIR.
- Performing optimization.
2. CompilationPlan
CompilationPlan is
the major class, which instructs the optimizing compiler how to
optimize a given method. Its constructor constructs a compilation
plan, as the name indicates. This includes the instance of
NormalMethod, the
method to be optimized. An array of TypeReference is
used in place of those defined in the method.
This also contains an
object of InstrumentationPlan, defining
how to instrument a method to gather the run time measurement
information. The methods initInstrumentation()
and finalizeInstrumentation()
are called at the beginning of the compilation, and after the
compilation just before the method is executed, respectively.
A compilation plan is
executed by executing each element in the optimization plan, by
calling the method execute().
The compiler queries the InlineOracle
interface to decide whether to inline a call site. If there is some
instrumentation to be performed, initialization takes place. After
the instrumentation, finalization takes place to clean up. However,
the finalization will not be executed, if this fails with an
exception.
3. OptimizationPlanElement
Class diagram of OptimizationPlanElement |
An array of
OptimizationPlanElement
defines the compilation steps. OptimizationPlanElement thus
represents an element in the optimization plan. Instances of the sub
classes of the abstract class OptimizationPlanElement are held in
OptimizationPlanner.masterPlan,
and hence they represent the global state. It is incorrect to store
any per-compilation state in the instance field of these objects.
OptimizationPlanner specifies the order of execution during the HIR
and LIR phases for a method. The method reportStats()
generates a report on time spent performing the element.
The method
shouldPerform()
determines whether the optimization plan should be performed and be
part of the compilation plan, by consulting the passed OptOptions
object. When an element is included, all the aggregate elements that
the element is a component of, are included too. The work represented
by the element is done in the optimization plan, by perform().
The work done is assumed to
modify the Intermediate Representation (IR)
in some way. The perform() of the aggregate element will invoke all
the elements' perform().
A client is a compiler driver that constructs a specific
optimization plan by including all the OptimizationPlanElements
from the master plan, that are appropriate for this compilation
instance.
4. OptimizationPlanAtomicElement
The
final class OptimizationPlanAtomicElement extends
OptimizationPlanElement. This object consists of a single compiler
phase in the compiler plan. The main work of the class is done by its
phase, which is an instance of the class CompilerPhase.
Each phase overrides this abstract class, and specifically the
abstract methods perform(), which
does the actual job, and getName(), which
gets the name of the phase. A
new instance of the phase is created when shouldPerform() is called,
and is discarded as soon as the method is finished.
Hence, the per-compilation state is contained in the instances of the
sub classes of CompilerPhase, as the state is not stored in the
element.
5. OptimizationPlanCompositeElement
Similarly,
OptimizationPlanCompositeElement
is the base class of all the elements in the compiler plan that
aggregates together the other OptimizationPlan elements, as depicted
in the Figure. Here an array of OptimizationPlanElement is kept to store the
elements that compose this composite element. The constructor
composes together the elements passed through as a method parameter,
into the composite element. If the phase wants the IR to be dumped
before or after it runs, it can be enabled using printingEnabled().
By default, this is disabled, where the sub classes are free to
override this method, and make it true.
This post continues at JikesRVM Optimizing (JIT) Compiler - II.
This post continues at JikesRVM Optimizing (JIT) Compiler - II.
No comments:
Post a Comment
You are welcome to provide your opinions in the comments. Spam comments and comments with random links will be deleted.