PHP 8.0: JIT

Version8.0
TypeNew Feature

PHP 8.0 brings support for Just-In-Time Compilation (JIT).

Pure interpreted programming languages has no compilation step, and directly executes the code in a virtual machine. Most of the interpreted languages including PHP, in fact, has a light-weight compilation step to improve its performance.

Programming languages with Ahead-Of-Time (AOT) compilation, on other hand requires the code to be compiled first before it runs.

Just-In-Time compilation is a hybrid model of interpreter and Ahead-of-Time compilation, that some or all of the code is compiled, often at run-time, without requiring the developer to manually compile it.


PHP was historically an interpreted language, that all of the code was interpreted by a virtual machine (Zend VM). This was changed with the introduction of Opcache and Opcodes, which were generated from the PHP code, and can be cached in memory. PHP 7.0 added the concept of AST (Abstract Syntax Tree), that further separated the parser from the compiler.

PHP's JIT internally uses DynASM from LuaJIT, and as implemented as part of the Opcache.


JIT In Depth
A detailed guide on optimal JIT configuration, benchmarks, and how JIT works in detail


PHP JIT chart


Opcache can inspect the used code, commonly called hot code, and store the compiled versions of them within the shared Opcache memory. When the code should be compiled, and what code should be compiled is configurable.

Platform Support

JIT is currently enabled on Linux and Windows systems running on x86 and x64 processor instruction sets. Apple M1, and ARM CPUs are currently not supported.

DynASM, which is the underlying assembler used in PHP JIT, supports ARM instructions as well, but it is not clear if PHP JIT can be run on ARM processors yet.

JIT also makes use of AVX if it is supported on the CPU. Most consumer and server grade processors from 2011 and later support AVX instructions. cat /proc/cpuinfo | grep avx run on most POSIX systems should reveal if the processor supports it.

Configuring JIT

In PHP 8.0, JIT is enabled by default, but turned off. Enabling JIT is easy, and only requires minimal INI configuration similar to this:

opcache.enable=1
opcache.enable_cli=1
opcache.jit_buffer_size=256M

Enable Opcache (opcache.enable)

JIT is implemented as part of Opcache, and requires the Opcache extension to be enabled.

opcache.enable=1
opcache.enable_cli=1

opcache.enable=1 directive does not enable Opcache for CLI, and requires opcache.enable_cli=1. It is possible to turn off Opcache (and this JIT) for other SAPIs (such as FPM), and enable Opcache only for CLI with opcache.enable_cli directive.

Set Buffer Size (opcache.jit_buffer_size)

The effective toggle for JIT is opcache.jit_buffer_size. It accepts how much memory JIT is allowed to use for its buffer.

The default value 0, which effectively disables JIT.

To enable and set a buffer size, set a positive value in bytes, or with standard PHP data size suffixes (M, G, etc.)

opcache.jit_buffer_size=256M

Additional JIT Configuration Options

The following configuration options are available, but they are set to appropriate defaults.

Set JIT flags (opcache.jit)

opcode.jit is a somewhat complicated configuration value. It accepts disable, on, off, trace, function, and a 4-digit value (not a bitmask) of 4 different flags in the order.

  • disable: Completely disables JIT feature at start-up time, and cannot be enabled run-time.
  • off: Disabled, but it's possible to enable JIT at run-time.
  • on: Enables tracing mode.
  • tracing: An alias to the granular configuration 1254.
  • function: An alias to the granular configuration 1205.

Granular Configuration

In addition to the tracing and function aliases, the opcache.jit directive accepts a 4-digit configuration value as well. it can further configure the JIT behavior.

The 4-digit configuration value is in the form of CRTO, where each position allows a single digit value for the flag designated by the letter.

For the full configuration options, see JIT Flags.

The default value is tracing, which compiles hot code (call-graph) while the code is being run (tracing), and enables use of CPU registers and AVX extension.

JIT In Depth
A detailed guide on optimal JIT configuration, benchmarks, and how JIT works in detail

Debugging JIT (opcache.jit_debug)

PHP JIT provides a way to emit JIT debug information by setting an INI configuration. When set, it outputs the assembly code for further inspection.

opcache.jit_debug=1

The opcache.jit_debug directive accepts a bit-mask value to toggle certain features. It currently accepts a value in the range of 1 (0b1) to 20 bits binary. A value of 1048576 represents the maximum level of debug output.

php -d opcache.jit_debug=1 test.php
TRACE-1$/test.php$7: ; (unknown)
    sub $0x10, %rsp
    mov $EG(jit_trace_num), %rax
    mov $0x1, (%rax)
.L1:
    cmp $0x4, 0x58(%r14)
    jnz jit$$trace_exit_0
    cmp $0x4e20, 0x50(%r14)
    ...

More Configuration Options

JIT supports several other configuration options to tune how many function calls makes it a "hot" function, which JIT then compiles, and a threshold to consider which functions to JIT, based on the percentage of overall function calls.

For a full list, see Opcache Configuration.


JIT Flags

The opcache.jit directive accepts a 4-digit value to control the JIT behavior, in the form of CRTO, and accepts following values for C, R, T, and O positions.

C: CPU-specific Optimization Flags

  • 0: Disable CPU-specific optimization.
  • 1: Enable use of AVX, if the CPU supports it.

R: Register Allocation

  • 0: Don't perform register allocation.
  • 1: Perform block-local register allocation.
  • 2: Perform global register allocation.

T: Trigger

  • 0: Compile all functions on script load.
  • 1: Compile all functions on first execution.
  • 2: Profile first request and compile the hottest functions afterwards.
  • 3: Profile on the fly and compile hot functions.
  • 4: Currently unused.
  • 5: Use tracing JIT. Profile on the fly and compile traces for hot code segments.

O: Optimization Level

  • 0: No JIT.
  • 1: Minimal JIT (call standard VM handlers).
  • 2: Inline VM handlers.
  • 3: Use type inference.
  • 4: Use call graph.
  • 5: Optimize whole script.

The option 4 under Triggers (T=4) did not make it to the final version of JIT implementation. It was trigger JIT on functions declared with @jit DocBlock comment attribute. This is now unused.


Backwards Compatibility Impact

None. JIT is a new feature added in PHP 8.0, and should not cause any issues. PHP does not raise any warnings or errors when it encounters unknown INI directives, which means setting JIT INI directives would not cause any issues.

Related Changes


RFC Discussion Implementation