IonMonkey/Overview: Difference between revisions

From MozillaWiki
Jump to navigation Jump to search
(Created page with "IonMonkey compilation occurs in four major overall phases: *'''MIR Generation'''. This phase transforms SpiderMonkey's bytecode into a control-flow graph and an architecture-inde...")
 
No edit summary
Line 1: Line 1:
=Modus Operandi=
IonMonkey has two major goals:
#Have a well-engineered design that easily supports adding new optimizations.
#Allow for specialization needed to generate extremely fast code.
To support 1, IonMonkey has a somewhat highly abstracted codebase with many files. This document serves to help navigate them and the compiler framework.
To support 2, IonMonkey follows in the tracing JIT's stead. It supports optimistic assumptions about the effects and results of operations, and allows these assumptions to flow throughout the generated code. Like the tracer, this requires ''guards''. Guards are strategically placed checks which will cause ''deoptimization'' if the check fails.
For example, consider an Ion-generated method having a 32-bit addition. If the addition operation overflows, or say it relies on an object access which happens to return a double, the compiled code is no longer valid. Guards check these assumptions, and when they fail, the method's execution resumes in the interpreter (and may later be recompiled).
=Pipeline=
IonMonkey compilation occurs in four major overall phases:
IonMonkey compilation occurs in four major overall phases:
*'''MIR Generation'''. This phase transforms SpiderMonkey's bytecode into a control-flow graph and an architecture-independent, SSA-form IR.  
*'''MIR Generation'''. This phase transforms SpiderMonkey's bytecode into a control-flow graph and an architecture-independent, SSA-form IR.  
*'''Optimization'''. The MIR analyzed and optimized. This is where global value numbering (GVN) and loop-invariant code motion (LICM) occur.
*'''Optimization'''. The MIR is analyzed and optimized. This is where global value numbering (GVN) and loop-invariant code motion (LICM) occur.
*'''Lowering'''. The MIR is transformed into an architecture-specific IR (still in SSA form) called LIR. Register allocation occurs on LIR.
*'''Lowering'''. The MIR is transformed into an architecture-specific IR (still in SSA form) called LIR. Register allocation occurs on LIR.
*'''Code generation'''. The LIR is transformed into native assembly for x86, x64, or ARM (or what have you).
*'''Code generation'''. The LIR is transformed into native assembly for x86, x64, or ARM (or what have you).
Line 16: Line 29:


Lastly, if you're interested in porting IonMonkey to a new CPU architecture, you might want to take a look at [[IonMonkey/Porting]].
Lastly, if you're interested in porting IonMonkey to a new CPU architecture, you might want to take a look at [[IonMonkey/Porting]].
=Runtime=
IonMonkey does not interact with the VM in the same way as the interpreter. It does not build interpreter stack frames and does not maintain an interpreter-readable stack. However, IonMonkey does create its own stack frames, and may need to translate these frames back to interpreter frames (and vice-versa). These concepts are explored below.
*[[IonMonkey/Frames]]
*[[IonMonkey/Bailouts]]

Revision as of 06:10, 15 August 2011

Modus Operandi

IonMonkey has two major goals:

  1. Have a well-engineered design that easily supports adding new optimizations.
  2. Allow for specialization needed to generate extremely fast code.

To support 1, IonMonkey has a somewhat highly abstracted codebase with many files. This document serves to help navigate them and the compiler framework.

To support 2, IonMonkey follows in the tracing JIT's stead. It supports optimistic assumptions about the effects and results of operations, and allows these assumptions to flow throughout the generated code. Like the tracer, this requires guards. Guards are strategically placed checks which will cause deoptimization if the check fails.

For example, consider an Ion-generated method having a 32-bit addition. If the addition operation overflows, or say it relies on an object access which happens to return a double, the compiled code is no longer valid. Guards check these assumptions, and when they fail, the method's execution resumes in the interpreter (and may later be recompiled).

Pipeline

IonMonkey compilation occurs in four major overall phases:

  • MIR Generation. This phase transforms SpiderMonkey's bytecode into a control-flow graph and an architecture-independent, SSA-form IR.
  • Optimization. The MIR is analyzed and optimized. This is where global value numbering (GVN) and loop-invariant code motion (LICM) occur.
  • Lowering. The MIR is transformed into an architecture-specific IR (still in SSA form) called LIR. Register allocation occurs on LIR.
  • Code generation. The LIR is transformed into native assembly for x86, x64, or ARM (or what have you).

The full pipeline is roughly outlined with the following diagram:

Ionmonkey overview.png

Each major phase of the pipeline is separated into four articles:

Lastly, if you're interested in porting IonMonkey to a new CPU architecture, you might want to take a look at IonMonkey/Porting.

Runtime

IonMonkey does not interact with the VM in the same way as the interpreter. It does not build interpreter stack frames and does not maintain an interpreter-readable stack. However, IonMonkey does create its own stack frames, and may need to translate these frames back to interpreter frames (and vice-versa). These concepts are explored below.