1. 10
    1. 7

      It’s a shame JavaScriptCore, the WebKit JavaScript engine doesn’t get more attention. They have a four-tier system that’s really nicely designed:

      • Tier 1 is a bytecode interpreter. This is hand-written macro assembly, which is carefully designed to fit into the L1 instruction cache on most machines, which makes it very fast to run. This stage records various bits of profiling information.
      • Tier 2 is the baseline JIT. This mostly uses the same code as tier 1, but either inlines the assembly implementing the bytecodes or inserts a call to a routine implementing complex bytecodes, avoiding any of the interpreter jump-threading overhead. This uses exactly the same stack-frame layout as tier 1, so on-stack replacement is trivial: if you’re in a loop in tier 1 and discover it’s being executed a load of times, you can quickly JIT the loop and continue.
      • Tier 3 is the CFG JIT. This is a continuation-passing-style IR that takes the profiling information (particularly type information) from tiers 1 and 2 and can compile larger functions from traces through a JavaScript program.
      • Tier 4 takes the output from the CFG JIT, converts it to SSA form, does a few more optimisations on it, and then runs it through a more expensive register allocator. Originally this was LLVM (which led to the fun acronym FTL for Fourth-Tier LLVM) but is now a lighter-weight Bare-Bones Backend (B3) because it was only benefitting from a tiny subset of LLVM.
      1. 1

        CFG […] can compile larger functions from traces through a JavaScript program.

        Do you mean it can compile loops down to straight-line code across function boundaries? Put another way – does TraceMonkey’s spirit live on? 🙂 If so – cool!

        1. 1

          I can’t remember if it’s actually a trace-based JIT or whether it just does inlining of hot paths. The effect is pretty similar either way: hot code paths are inlined into the unit that is compiled as a single ‘function’ in the back end.