IonMonkey/Overview

From MozillaWiki
Jump to: navigation, search

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).

When a guard fails, it is called a bailout, which is explained later.

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

Articles about the IonMonkey pipeline:

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.

File Layout

All IonMonkey files are contained in js/src/jit. The entry point is jit/Ion.cpp, which mostly contains random assorted small functions for IonCode, IonScript, and IonCompartment. The rest are:

  • Helpers:
    • BitSet.* - An efficient arbitrary-size bitset implementaton.
    • C1Spewer.* - Spew for the C1 visualizer.
    • FixedArityList.h - Template for declaring fixed-length vectors.
    • InlineList.h - Templates for threading linked lists through objects.
    • IonAllocPolicy.h - IonMonkey's pool-based allocator.
    • IonSpewer.* - Debug spew helpers.
    • JSONSpewer.* - Debug spew in JSON form.
  • Data Structures:
    • IonCode.h - Declaration for IonCode, IonScript.
    • IonCompartment.h - Declaration for IonCompartment.h.
    • IonFrames.h - Layout of Ion frames.
  • MIR Generation:
    • IonBuilder.* - Translation from bytecode to MIR.
    • MIR.* - MIR class and instruction hierarchy.
    • MIRGenerator.h - Not really anything, this should be renamed.
    • MIRGraph.* - Control flow graph and basic blocks.
    • MOpcodes.h - MIR opcodes.
  • Analyses:
    • IonAnalysis.cpp - Small, assorted analysis passes.
    • RangeAnalysis.cpp - A pass for range analysis.
    • LICM.* - Loop-invariant code motion.
    • TypeOracle.h - Interface for type oracles.
    • TypePolicy.* - Rules for how MIR is specialized and how conversions are inserted.
    • ValueNumbering.* - Global value numbering.
  • LIR Generation:
    • Lowering.* - Entry point to LIR generation. Contains LIRGenerator.
    • IonLIR.* - Interfaces for LIR instructions and their inputs, as well as LIR blocks and graphs.
    • LIR-Common.* - LIR instructions shared by all platforms.
    • LOpcodes.* - LIR opcodes shared by all platforms.
      • x86-shared/Lowering-x86-shared.* - LIR generation that is shared between x86 and x64.
      • <arch>/Lowering-<arch>.* - LIR generation specific to <arch>.
      • <arch>/LIR-<arch>.h - LIR instructions specific to <arch>.
      • <arch>/LOpcodes-<arch>.h - LIR opcodes specific to <arch>.
  • Code generation logic:
    • GreedyAllocator.* - Greedy register allocator.
    • LinearScan.* - Linear scan register allocator.
    • CodeGenerator.* - Entry point to code generation and contains a lot of shared code.
      • shared/CodeGenerator-shared.* - Code generation logic that can be re-used among all architectures.
      • shared/CodeGenerator-x86-shared.* - Code generation that is shared between x86 and x64.
      • <arch>/CodeGenerator-<arch>.* - Code generation specific to <arch>.
    • MoveResolver.* - Performs cycle detection and topological sorting of parallel moves.
    • shared/MoveEmitter-x86-shared.* - Emits a sequence of parallel moves that have been cycle-detected and topologically sorted.
    • <arch>/StackAssignment-<arch>.h - Helper for allocating stack slots during register allocation.
  • Code generation bit-banging:
    • <arch>/Architecture-<arch>.h - Information about the architecture, such as which registers are available, their names, the calling convention, stack properties, etc.
    • IonRegisters.h - C++ helpers and classes for interacting with registers.
    • IonMacroAssembler.h - Entry point to assembling native code. Contains platform-neutral helpers.
    • shared/MacroAssembler-x86-shared.h - Contains abstracted assembler logic shared between x86 and x64.
      • <arch>/MacroAssembler-<arch>.h - Contains abstracted assembler logic for x86.
    • Assembler-shared.h - Data structures used for assembling native code.
      • x86-shared/Assembler-x86-shared.h - Instruction set shared between x86 and x64.
      • <arch>/Assembler-<arch>.* - Instruction set helpers specific to <arch>.
    • IonLinker.h* - Moves generated assembly into executable memory.
  • Runtime support:
    • Bailouts.* - Logic for resuming Ion methods in the interpreter.
      • <arch>/Bailouts-<arch>.* - Platform-specific bailout helpers.
    • <arch>/Trampolines-<arch>.cpp - Platform-specific trampolines requires to enter and exit Ion code.