LuaJIT Features

LuaJIT

# LuaJIT Features

LuaJIT tries to keep the spirit of Lua — it's light-weight, efficient and extensible.

## Features

All functions are by default compiled Just-In-Time (JIT) to machine code:

- Functions that are unused are not compiled at all.
- Compilation can be enabled/disabled selectively for individual functions and subfunctions or even whole modules.
- Interpreted and compiled functions can be freely mixed.

Ahead-Of-Time (AOT) compilation (at runtime) is supported, too:

- A number of API functions and command line options allows full user control over the compilation process.

The JIT compiler is extensible:

- The optimizer is an extra module that attaches to the compiler pipeline.
- Various modules provide trace and debug information about the compilation process.
- All of these features can be activated with command line options.

## Performance

The compiled machine code is very efficient:

- Have a look at some Performance Measurements.
- Aggressive optimizations (specialization, inlining) are enabled wherever possible. Inlined contracts catch wrong optimizer predictions at runtime (undetected polymorphism).
- Adaptive deoptimization is used to recompile individual bytecode instructions with broken contracts. This avoids generating code for the generic fallback cases most of the time (faster compilation, reduced I-cache contention).
- Special CPU features (such as conditional moves or SSE2) are automatically used when detected.

The JIT compiler is very fast:

- Compilation times vary a great deal (depending on the nature of the function to be compiled) but are generally in the microsecond range.
- Even compiling large functions (hundreds of lines) with the maximum optimization level takes only a few milliseconds in the worst case.

LuaJIT is very small:

- The whole JIT compiler engine adds only around 32K of code to the Lua core (if compiled with `-Os`).
- The optimizer is split into several optional modules that can be loaded at runtime if requested.
- LuaJIT adds around 6.000 lines of C and assembler code and 2.000 lines of Lua code to the Lua 5.1 core (17.000 lines of C).
- Required build tools (DynASM) take another 2.500 lines of Lua code.

## Compatibility

LuaJIT is designed to be fully compatible with Lua 5.1. It accepts the same source code and/or precompiled bytecode. It supports all standard language semantics. In particular:

- All standard types, operators and metamethods are supported.
- Implicit type coercions (number/string) work as expected.
- Full IEEE-754 semantics for floating point arithmetics (NaN, +-Inf, +-0, ...).
- Full support for lexical closures. Proper tail calls do not consume a call frame.
- Exceptions are precise. Backtraces work fine.
- Coroutines are supported with the help of Coco.
- No changes to the Lua 5.1 incremental garbage collector.
- No changes to the standard Lua/C API.
- Dynamically loaded C modules are link compatible with Lua 5.1 (same ABI).
- LuaJIT can be embedded into an application just like Lua.

Some minor differences are related to debugging:

- Debug hooks are only called if debug code generation is enabled.
- There is no support for tailcall counting in JIT compiled code. HOOKTAILRET is not called, too. Note: this won't affect you unless you are writing a Lua debugger. *

* There is not much I can do to improve this situation without undue complications. A suggestion to modify the behaviour of standard Lua has been made on the mailing list (it would be beneficial there, too).

## Restrictions

- Only x86 (i386+) CPUs are supported right now (but see below).
- Only the default type for `lua_Number` is supported (`double`).
- The interrupt signal (Ctrl-C) is ignored unless you enable debug hooks (with `-j debug`). But this will seriously slow down your application. I'm looking for better ways to handle this. In the meantime you have to press Ctrl-C twice to interrupt a currently running JIT compiled function (just like C functions).
- GDB, Valgrind and other debugging tools can't report symbols or stack frames for JIT compiled code. This is rather difficult to solve. Have a look at Debugging LuaJIT, too.

## Caveats

- LuaJIT allocates executable memory for the generated machine code if your OS has support for it: either `HeapCreate()` for Windows or `mmap()` on POSIX systems.
  The fallback is the standard Lua allocator (i.e. malloc()). But this usually means the allocated memory is not marked executable. Running compiled code will trap on CPUs/OS with the NX (No eXecute) extension if you can only use the fallback.
- DynASM is needed to regenerate the `ljit_x86.h` file. But only in case you want to modify the `*.dasc`/`*.dash` files. A pre-processed `*.h` file is supplied with LuaJIT.
  DynASM is written in Lua and needs a plain copy of Lua 5.1 (installed as `lua`). Or you can run it with LuaJIT built from the `*.h` file supplied with the distribution (modify `DASM=` in `src/Makefile`). It's a good idea to install a known good copy of LuaJIT under a different name for this.
- LuaJIT ships with `LUA_COMPAT_VARARG` turned off. I.e. the implicit `arg` parameter is not created anymore. Please have a look at the comments in `luaconf.h` for this configuration option. You can turn it on, if you really need it. Or better yet, convert your code to the new Lua 5.1 vararg syntax.

## TODOs

- Work on LuaJIT 2.x is in progress. For more details please check the » LuaJIT roadmap 2008.

Copyright © 2005-2008 Mike Pall · Contact