Write Barriers in JIT Compilers

In languages like Java where garbage collector (GC) is used for cleaning up the unused references. The idea of write barriers is used at runtime to communicate with GC for letting the GC know the set of objects that needs to be tracked due to object pointers getting stored in another object and classes.

The JIT compiler is required to insert a write barrier in the code which it generates to maintain the function correctness.

The write barriers are normally used after following situations:

  • If there is a store of a reference to a field in an object (either static or an instance field).
  • if there is a store of a reference into an array element.
  • If there is an arraycopy of reference.

Having write barriers in the code is an overhead. So there are some optimizations that can be performed to reduce the number of write barriers that are required in the JIT compiled code. JIT performance can be greatly improved if the operations/checks performed by the write-barrier can be inlined.

There are four major checks that are performed in the write barrier.

  1. Nullness Check: Check if a store like (a.f = b) is performed to a null object. This can checked both at compile time and at runtime.

  2. Generational Check: The generational garbage collector divides the heap in two part; a young generation space where the newly created object resides(GC happens frequently) and a tenured space (old generation) where long-lived objects resides (GC doesn’t happen frequently). (Note that the young generation is further divided into one Eden and two Survivor spaces). And now for store statement like (a.f=b) where b is in young generation and a is in old generation, the GC should remember to scan the object (a) stored in old generation.

  3. Heap Object Check: While executing JIT compiled code there is possibility that an object might get allocated on method’s stack-frame. There can be situations where we can not determine whether the object is on heap or stack, so a runtime check is required to determine the same. Note: A stack-allocated object doesn’t required a write barrier check.

  4. Concurrent Mark Check: Marking set of objects for garbage collection can be performed concurrently. A special thread can be used to just mark the set of live objects. However if an object b is stored into an object a that has already been scanned by the concurrent thread then object a need to be rescanned to ensure the functional correctness.