Definition
JIT compilation is compilation of a computer code during execution of a program (at run time). Whenever a program, while running, creates and runs some new executable code which was not part of the program when it was stored on disk, it’s a JIT
Overview
JIT can be divided into two distinct phases:
- Create machine code at program run-time
- Execute that machine code, also at program run-time
Machine Code Creation
It is where 99% of the challenges of JITing are. This is exactly what a compiler does. The machine code is emitted into an output stream, but it could be just kept in memory, both gcc
and clang
can keep the code in memory for JIT execution
Machine Code Execution
Suppose we want to dynamically create this C
function in memory and execute it:
Here is the C
code:
The main 3 steps performed by this code are:
- Use
mmap
to allocate a readable, writable and executable chunk of memory on the heap - Copy the machine code implementing
add4
into this chunk - Execute code from this chunk by casting it to a function pointer and calling through it
Note that step 3 can only happen because the memory chunk containing the machine code is executable. Without setting the right permission, that call would result in a runtime error from the OS. This would happen if, for example, we allocated m
with a regular call to malloc
, which allocates readable and writable, but not executable memory