The FTL JIT is JavaScriptCore's top-tier optimizing compiler. It's a combination of our DFG compiler for doing high-level optimizations and type inference, and a lowering phase that turns that code into C-like SSA.

The FTL JIT started out as a marriage of the DFG and LLVM, but later LLVM backend was replaced with B3.

See for the bug that tracked the original FTL JIT work. This was done as part of our effort to increase our latency-throughput adaptability range, and included other things like our concurrent JIT implementation; all of the tasks involved can be seen in A lot of the future work to further improve the FTL JIT is tracked under The work to transition the FTL JIT to B3 is tracked by

The FTL JIT is enabled by default on the Mac and iOS ports.

Two detailed blog posts have been written about the FTL; they currently serve as the best documentation of the FTL's architecture; see: and


The FTL is integrated as an alternative backend for the DFG JIT but largely reuses existing DFG functionality. The FTL differs from the DFG as follows:

  • Instead of generating machine code directly from the DFG IR, the DFG IR is lowered to a C-like SSA IR. The IR is abstracted by the FTL. We refer to it as "FTL output". FTL output can be configured to abstract over either LLVM IR or B3 IR. When configured to use LLVM, the FTL invokes the LLVM optimization pipeline and backend to generate machine code. That machine code is then managed by the JSC executable memory manager no differently than if it were generated by our own backends. When configured to use B3, the FTL tells B3 to optimize and generate the code using WebKit's MacroAssembler API. This leads to a natural integration between B3 and JSC executable memory management.
  • Additional DFG phases are used. Running in FTL mode causes the DFG to lower to SSA even before lowering to LLVM IR. Additional optimizations like LICM are performed on the DFG-SSA IR.

The FTL JIT supports key DFG concepts like OSR entry, OSR exit, concurrent compilation, and self-modifying code for inline caches that we use for things like GetById (i.e. v = o.f), PutById (i.e. o.f = v), Call/Construct, and In (i.e. "foo" in o).

Last modified 6 years ago Last modified on Nov 13, 2017 5:07:36 AM