JavaScript

Virtual Machines

JITs

GCs

Disclaimer

I’m not an expert, I’m just a JS developer who loves to know about the technology that runs his favorite language

And so should you!


I’m trying to give links/citations where possible

What I’m talking about

  • Architecture and staged jit compilation of V8
  • … and History of SpiderMonkey
  • (no other engines; there is hardly any public info about them)
  • Inline Caches (ICs)
  • (Generational) Garbage Collection
  • Some optimization pitfalls/suggestions

Javascript

Is the worlds most compiled language

(even though you don’t compile it yourself)

The browser compiles it over and over again,
every single time you load a web site.

Compilation needs to be insanely fast!

Dynamic (staged) recompilation

  • Stage 1: fast compiles, not so fast code
  • Stage 2: slow compiles, extremely fast code
  • Stage 1.5: in between, dynamic compiles, mostly fast code (ICs)


Be aware!
Stage 2 is very specialized, can “bail out” to stage 1
Not every code construct can be compiled in stage 2

V8

Stage 1: full-codegen

Stage 2: Crankshaft


  • good baseline with ICs
  • insanely fast optimized Crankshaft



http://wingolog.org/archives/2013/04/18/inside-full-codegen-v8s-baseline-compiler

SpiderMonkey (FF 3.5)

Stage 0: Interpreter

Stage 2: TraceMonkey


  • Records (traces) loops, replays them
  • extremely fast, but very fragile, bails out often

SpiderMonkey (FF4)

Stage 0: Interpreter

Stage 1: JägerMonkey

Stage 2: TraceMonkey


  • JägerMonkey compiles whole functions, not just loops
  • Bailouts still go to the Interpreter

SpiderMonkey (FF 9)

Stage 0: Interpreter

Stage 1: JägerMonkey + Type Inference

Stage 2: TraceMonkey


  • TI creates type specialized code, reducing chance of Bailouts

SpiderMonkey (FF 18)

Stage 0: Interpreter

Stage 1: JägerMonkey + Type Inference

Stage 2: IonMonkey


  • IM does advanced optimizations
  • Bailouts still go to the Interpreter


SpiderMonkey (FF 24)

Stage 0: Interpreter

Stage 1: Baseline

Stage 2: IonMonkey


  • Baseline uses ICs
  • Bailouts go to Baseline
  • Interpreter still useful for IIFE and similar

Inline Caches

Stage 1 generates native code, but most operations still fall back to generic C++ methods

ICs are type specialized snippets that are chained in front of the generic fallback

var a=3.14; -a;

bool
ICUnaryArith_Double::Compiler::generateStubCode(MacroAssembler &masm)
{
    Label failure;
    masm.ensureDouble(R0, FloatReg0, &failure);
 
    JS_ASSERT(op == JSOP_NEG);
    masm.negateDouble(FloatReg0);
    masm.boxDouble(FloatReg0, R0);
 
    EmitReturnFromIC(masm);

    // Failure case - jump to next stub
    masm.bind(&failure);
    EmitStubGuardFailure(masm);
    return true;
}
http://mxr.mozilla.org/mozilla-central/source/js/src/jit/BaselineIC.cpp#3087

Garbage Collection

Something is rotten in the state of Denmark

and Hamlet is taking out the trash!

http://www.youtube.com/watch?v=KqJTeyVnZu0

No, Srsly

You allocate *a lot* of objects and produce a lot of trash

“new”, object literals, …

The optimizing (stage 2) JITs can optimize most of it away

Stage 1 JITs will sometimes allocate for every single arithmatic

expression.

Taking out the trash costs, a lot.




http://www.youtube.com/watch?v=VhpdsjBUS3g

Generational GC

  • The cost of a GC is proportional to the number of live objects
  • Most objects are temporary with a short lifetime
  • How to combine those two principles?

  • Create two heaps, for short-lived and long-lived objects
  • Nursery collected frequently, most objects are dead, so collection is fast
  • Tenured heap is collected less frequently, most objects will stay alive anyway
  • Other advantage: memory compaction, less fragmentation

GGC in Firefox

  • GGC moves objects from nursery to tenured
  • GC runtime unpredictable
  • pointers will need to be changed
  • C++ code can have pointers to JS objects


  • Past: conservative scanning, everything that looks like a pointer is treated as one
  • false positives, but not harmful for GC
  • but *rewriting* those may lead to serious bugs


GGC in Firefox

http://arewefastyet.com/

Optimization?

Optimization tips

  • Move performance critical code to own function
  • Handle multiple dispatch and errors in outer function
  • Create all object properties in the constructor
  • Profile! Use the V8/node tools, like `--prof` and `node-tick-processor`
  • *Know* what you are doing :-)

JavaScript: VMs, JITs, GC

By Arpad Borsos

JavaScript: VMs, JITs, GC

  • 2,813