Jato Virtual Machine Internals
==============================
Pekka Enberg
2011

Introduction
------------

This manual documents the internals of the Jato virtual machine.

The reader is expected to have some basic knowledge of the C programming
language, Java Virtual Machine (JVM) architecture, and machine architecture.

- Java Virtual Machine specification

- Intel Manuals

- The Java Virtual Machine

Structure of the Virtual Machine
--------------------------------

Classes
~~~~~~~

TODO

Methods
~~~~~~~

TODO

Fields
~~~~~~

TODO

Objects
~~~~~~~

TODO

Exceptions
~~~~~~~~~~

TODO

Java Runtime Interface
----------------------

Structure of the Just-in-Time Compiler
--------------------------------------

Subroutine inlining
~~~~~~~~~~~~~~~~~~~

TODO

Control-Flow Graph Analysis
~~~~~~~~~~~~~~~~~~~~~~~~~~~

TODO

BC2IR
~~~~~

The JVM has a stack-based architecture which means instructions operate on a
stack. Modern CPUs, on the other hand, are register-based which means that
instructions operate on registers. One of the first things the JIT compiler
needs to do is to convert the stack-based bytecode into a register-based
intermediate representation. The algorithm that does the conversion is referred
to as BC2IR in literature. Entry point to the algorithm can be found in
jit/bytecode-to-ir.c::convert_to_ir().

Instruction Selection
~~~~~~~~~~~~~~~~~~~~~

The instruction selector takes the HIR as an input and outputs LIR. The actual
instruction selector is generated from a Monoburg rules file (e.g.
arch/x86/insn-selector_32.brg).

Static-Single Assignment (SSA) Form
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Static-Single Assignment Form is a representation form where every variable is
defined exactly once and every use of a variable refers at most one definition.
This intermediate representation form offers an uniform support for a large
group of data analysis problems, and many optimizations and data flow
algorithms are more efficient on the SSA form than on the normal Control Flow
Graph form.

Support for SSA form implies two major steps: translating from LIR form to SSA
form (lir_to_ssa function in jit/ssa.c) and translating from SSA form to LIR
form (ssa_to_lir function in jit/ssa.c). The back translation is needed because
the SSA form introduces virtual phi functions that cannot be processed by the
code emission stage. Between these two steps some optimizations can be applied.
Jato offers a simple variant of dead code elimination (jit/dce.c), copy folding
(__rename_variables in jit/ssa.c) and a simple variant of array bound check
elimination (jit/abc.c). All these optimizations are applied only if array
bounds check elimination is required.

Liveness analysis
~~~~~~~~~~~~~~~~~

- Use-def

Register allocation
~~~~~~~~~~~~~~~~~~~

Resolution Blocks
^^^^^^^^^^^^^^^^^

The resolution blocks were introduced to solve the problem with reloading
registers when jumping from one (source) basic block to another basic block
(destination).

Typically when you have a virtual register which has live ranges before source
block and in the destination block, what you must do is put MOV instructions at
the end of the source basic block which restore register value from a spill
slot. Actually you must put them before the JMP instruction if there is one at
the end of source block.

Now, it might be the case that the ending JMP instruction is using a virtual
register, which is allocated the same machine register as is to one of the
virtual registers which are reloaded. If movs are before the jump, then the
register which is used by JMP would by clobbered by those reload instructions
and we would not jump into the right place. This happens because register
allocator sees all those virtual registers as not live in the source block. As
one might think of many different solutions to this problem, introducing
resolution blocks was one that was probably the simplest one to implement. We
put reload MOVs into an intermediate block on each (?) edge to avoid the
problem of clobbering registers allocated to not-yet-dead virtual registers.

Code Generation
~~~~~~~~~~~~~~~

TODO

Intermediate Representations
----------------------------

The compiler uses two different intermediate representations: high-level
intermediate representation (HIR) in the frontend and low-level intermediate
representation (LIR) in the backend. The HIR is an abstract syntax tree (AST)
of the compiled bytecode whereas LIR is corresponds almost one-to-one to the
target machine instructions.

Both HIR and LIR are standard intermediate representations that are documented
in detail in, for example, <<Muchnick97>> and <<Burke99>>. Literature also
describes a middle-level intermediate representation (MIR) but the compiler
does not use that.

High-Level Intermediate Representation (HIR)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

For the front-end, we use a high-level intermediate representation (HIR) that
is a forest of expression trees. That is, a compilation unit (a method) is
divided into basic blocks that contain a list of statements and each statement
can operate on an expression tree. Examples of statements include STMT_STORE
that stores an expression to a local variable and STMT_IF that does conditional
branch. The simplest form of expression is EXPR_VALUE which represents a
constant value but there are more complex types of expressions including binary
operations (EXPR_BINOP) and method invocation (EXPR_INVOKE).

- struct statement

- struct expression

Low-Level Intermediate Representation (LIR)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

- struct operand

- struct insn

Machine Architecture Support
----------------------------

TODO

Application Binary Interface (ABI)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

TODO

Instruction Encoding
~~~~~~~~~~~~~~~~~~~~

TODO

[bibliography]
Bibliography
------------

- [[Muchnick97]] Steven Muchnick. 'Advanced Compiler Design and
  Implementation'. Morgan Kaufmann. 1997. ISBN 1558603204.

- [[Burke99]] Michael Burke et al. 'The Jalapeno Dynamic Optimizing Compiler
  for Java'. 1999.
