Introduction
LuaJIT is a Just-In-Time (JIT) compiler for the Lua programming language. Lua is a powerful, dynamic, and lightweight programming language that can be embedded or used as a general-purpose standalone language.
LuaJIT Copyright © 2005-2022 Mike Pall, released under the MIT open source license.
Compatibility
| Windows | Linux | BSD | macOS | POSIX |
|---|
| Embedded | Android | iOS |
|---|
| PS3 | PS4 | PS Vita | Xbox 360 |
|---|
| GCC | CLANG LLVM | MSVC |
|---|
| x86 | x64 | ARM | PPC | e500 | MIPS |
|---|
| Lua 5.1 API+ABI | + JIT | + BitOp | + FFI | Drop-in DLL/.so |
|---|
Overview
| 3x - 100x | 115 KB VM | 90 KB JIT | 63 KLOC C | 24 KLOC ASM | 11 KLOC Lua |
|---|
LuaJIT has been successfully used as scripting middleware in games, devices, networking and graphics applications, numerical simulations, trading platforms and many other professional applications. It scales from embedded devices, smartphones, desktops to server farms. It combines high flexibility, high performance and unparalleled low memory footprint.
LuaJIT has been continuously developed since 2005. It is widely regarded as one of the fastest dynamic language implementations. Since its initial release, it has outperformed other dynamic languages in many cross-language benchmarks—often by a large margin.
For LuaJIT 2.0, the entire VM has been rewritten from scratch and continuously optimized for performance. It combines a high-speed interpreter written in assembler with a state-of-the-art JIT compiler.
The innovative tracing compiler integrates advanced, SSA-based optimizations and a highly tuned code generation backend. The overhead associated with dynamic languages is significantly reduced, enabling it to break through the performance range traditionally reserved for offline static language compilers.
Download
Public Git Repository
The public git repository contains the current state of actively developed branches. You can clone it using the following command:
git clone https://luajit.org/git/luajit.git
Note: This is not a browsable resource, the repository is only accessible through git clients.
This creates a new directory tree under luajit. Change into it, switch to the branch you want to use and follow the usual build instructions. Use git pull to fetch updates from the (read-only) public repository. There's also a browsable mirror and a GitHub mirror.
The git master branch will be phased out and pinned to v2.0 branch. Please use versioned branches v2.1 or v2.0 instead.
Actively Developed Branch Releases
Released only occasionally. It is strongly recommended to follow the git branches.
Releases should be taken as snapshots of branches on a regular basis. Don't try to cherry-pick or backport individual changes, no matter how good individual changes look (because they usually aren't).
| Filename | Date | .tar.gz | .zip |
|---|---|---|---|
| LuaJIT-2.1.0-beta3 | 2017-05-01 | 1001K ▼ | 1130K ▼ |
| LuaJIT-2.0.5 | 2017-05-01 | 830K ▼ | 940K ▼ |
Historical Versions
This is a list of archived packages of historical versions. Please consider using actively developed versions unless you have special needs.
| Filename | Date | .tar.gz | .zip |
|---|---|---|---|
| LuaJIT-1.1.8 | 2012-04-16 | 362K ▼ | 423K ▼ |
| LuaJIT-1.0.3 | 2005-09-08 | 301K ▼ |
SHA256 Checksums
1ad2e34b111c802f9d0cdf019e986909123237a28c746b21295b63c9e785d9c3 LuaJIT-2.1.0-beta3.tar.gz
fcc4069bfaf909f762844d6404a8c5940591b00237ffce1781e887a0964140da LuaJIT-2.1.0-beta3.zip
874b1f8297c697821f561f9b73b57ffd419ed8f4278c82e05b48806d30c1e979 LuaJIT-2.0.5.tar.gz
95f655cff930781619f0fbbab707fb8c05f406d9007a3505c8243e3dbbfacec8 LuaJIT-2.0.5.zip
42f095d0215d76c29b7b040ad52dddc1783ffc6e3021b8a831627973a8a32862 LuaJIT-1.1.8.tar.gz
d59751726e6d3f22a4b3cfb158d728b8feea6aa3b9ee30af610685bc28b0e6c8 LuaJIT-1.1.8.zip
e39204aad8d2a3f9ef74a4a515fedf3cce3f55ff247af8ae50f2a8cb01f257c3 LuaJIT-1.0.3.tar.gz
Installation
LuaJIT is distributed only as source packages. This page describes how to build and install LuaJIT using different operating systems and C compilers.
For the Impatient (on POSIX Systems)
make && sudo make install
Requirements
System
LuaJIT currently works out of the box on most systems:
| OS | Min. Version | Requirements | LuaJIT Versions |
|---|---|---|---|
| Windows | 7 | x86 or x64, ARM64: TBA | v2.0 – |
| Linux | v2.0 – | ||
| *BSD | v2.0 – | ||
| macOS (OSX) | 10.4 | v2.1 – | |
| POSIX | mmap, dlopen | v2.0 – | |
| Android | 4.0 | Recent Android NDK | v2.0 – |
| iOS | 3.0 | Xcode iOS SDK | v2.1 – |
| PS3 | PS3 SDK | v2.0 – v2.1 EOL | |
| PS4 | PS4 SDK (ORBIS) | v2.0 – | |
| PS5 | PS5 SDK (PROSPERO) | v2.1 – | |
| PS Vita | PS Vita SDK (PSP2) | v2.0 – v2.1 EOL | |
| Xbox 360 | Xbox 360 SDK (XEDK) | v2.0 – v2.1 EOL | |
| Xbox One | Xbox One SDK (DURANGO) | v2.1 – | |
| Nintendo Switch | NintendoSDK + NX Addon | v2.1 – |
The codebase defines compatibility for more systems, but there is no official support.
Toolchain
Building LuaJIT requires a recent toolchain based on GCC, Clang/LLVM or MSVC++.
The Makefile-based build system requires GNU Make and supports cross-building. Batch files are provided for building with MSVC++ and for cross-building to consoles.
CPU Architecture
| CPU | Bits | Requirements | Variants | LuaJIT Versions |
|---|---|---|---|---|
| x86 | 32 | v2.1+: SSE2 | v2.0 – | |
| x64 | 64 | v2.0 – | ||
| ARM | 32 | ARMv5+, ARM9E+ | hard-fp + soft-fp | v2.0 – |
| ARM64 | 64 | ARM64le + ARM64be | v2.1 – | |
| PPC32 | 32 | hard-fp + soft-fp | v2.0 – v2.1 EOL | |
| PPC/e500 | 32 | e500v2 | v2.0 EOL | |
| MIPS32 | 32 | MIPS32r1 – r5 | hard-fp + soft-fp | v2.0 – |
| MIPS64 | 64 | MIPS64r1 – r5 | hard-fp + soft-fp | v2.1 – |
| MIPS64 | 64 | MIPS64r6 | hard-fp + soft-fp | v2.1 EOL |
| RISC-V | 64 | RVA22+ | TBA |
No plans to add historical architectures or continue support for obsolete (EOL) architectures, as no new CPUs are typically available. Similarly, there are no plans to support marginal and/or de facto dead architectures.
Configuring LuaJIT
The standard configuration should work for most installations. Usually no adjustments are needed. The following files contain all user-configurable settings:
src/luaconf.hsets some configuration variables.Makefilehas settings for installing LuaJIT (POSIX only).src/Makefilehas settings for compiling LuaJIT under POSIX, MinGW or Cygwin.src/msvcbuild.bathas settings for compiling LuaJIT with MSVC (Visual Studio).
Before changing any settings, read the instructions in these files.
POSIX Systems (Linux, macOS, *BSD, etc.)
Prerequisites
Depending on your distribution, you may need to install GCC packages, development headers and/or a full SDK. For example, on current Debian/Ubuntu, install libc6-dev using the package manager.
The recommended way to get the latest version is to pull from the git repository.
Or download the latest LuaJIT source package (choose .tar.gz). Move it to your chosen directory, open a terminal window and change to that directory. Now unpack the archive and change to the newly created directory (replace XX.YY.ZZ with the version you downloaded):
tar zxf LuaJIT-XX.YY.ZZ.tar.gz
cd LuaJIT-XX.YY.ZZ
Building LuaJIT
The provided Makefiles try to automatically detect the settings needed for your operating system and compiler. They require running with GNU Make, which is probably the default on your system anyway. Just run:
make
This always builds a native binary, depending on the host operating system you run this command on. Check the cross-compilation section for more options.
By default, only the prefix /usr/local is searched for modules. You can add extra prefixes to the search path by appending the PREFIX option, for example:
make PREFIX=/home/myself/lj2
Please use the LuaJIT 2.1 branch to compile for **macOS (OSX)**.
Installing LuaJIT
The top-level Makefile installs LuaJIT under /usr/local by default, with executables ending up in /usr/local/bin and so on. You need root privileges to write to this path. So assuming sudo is installed on your system, run the following command and enter your sudo password:
sudo make install
Otherwise specify the directory prefix as an absolute path, for example:
make install PREFIX=/home/myself/lj2
Obviously, the prefix given during build and installation needs to be the same.
Windows
Install one of the open source SDKs (MinGW or Cygwin), wich comes with a modified GCC and the required development headers. Or install Microsoft's Visual Studio (MSVC).
Next, extract from the git repository or download the source package and unpack it with an archive manager (like Windows Explorer) to your chosen directory.
Building with MSVC
Open the "Visual Studio Command Prompt" (x86 or x64), cd to the directory where you unpacked the source code and run the following command:
cd src
msvcbuild
Check the msvcbuild.bat file for more options. Then follow the installation instructions below.
Building with MinGW or Cygwin
Open a command prompt window and make sure MinGW or Cygwin programs are in your path. Then cd to the git repository directory or the directory where you unpacked the source. Then run this command for MinGW:
mingw32-make
Or this command for Cygwin:
make
Then follow the installation instructions below.
Installing LuaJIT
Copy luajit.exe and lua51.dll (built in the src directory) to a newly created directory (anywhere is fine). Add the lua and lua\jit directories underneath and copy all Lua files from the distribution's src\jit directory to the latter directory.
There are no hardcoded absolute path names—all modules are loaded relative to the directory where luajit.exe is installed (see src/luaconf.h).
Cross-compiling LuaJIT
The GNU Makefile-based build system allows cross-compiling for any supported target on any host, as long as both architectures have the same pointer size. If you want to cross-compile to any 32-bit target on a 64-bit OS, you need to install the multilib development package (e.g. libc6-dev-i386 on Debian/Ubuntu) and build the 32-bit host part (HOST_CC="gcc -m32").
Whenever the host operating system and target operating system differ, you need to specify TARGET_SYS, otherwise you'll get assembler or linker errors. For example, if you're compiling for embedded Linux or Android on Windows or macOS hosts, you need to add TARGET_SYS=Linux to the examples below. For minimal target operating systems, you may need to disable the built-in allocator in src/Makefile and use TARGET_SYS=Other. Don't forget to specify the same TARGET_SYS for the installation step.
The examples below only show some popular targets—please check the comments in src/Makefile for more details.
# Cross-compile to a 32 bit binary on a multilib x64 OS
make CC="gcc -m32"
# Cross-compile on Debian/Ubuntu for Windows (mingw32 package)
make HOST_CC="gcc -m32" CROSS=i586-mingw32msvc- TARGET_SYS=Windows
The CROSS prefix allows specifying standard GNU cross-compilation toolchains (Binutils, GCC and matching libc). The prefix may vary depending on the --target of your build toolchain (note the "-" after the CROSS prefix). The following example uses the canonical toolchain triplets for Linux.
Since there's usually no simple way to detect CPU features at runtime, it's important to compile with the correct CPU or architecture settings. You can specify these when building your toolchain yourself. Or add -mcpu=... or -march=... to TARGET_CFLAGS. For ARM, having the correct -mfloat-abi=... setting is also important. Otherwise LuaJIT may not run at the full performance of the target CPU.
# ARM soft-float
make HOST_CC="gcc -m32" CROSS=arm-linux-gnueabi- \
TARGET_CFLAGS="-mfloat-abi=soft"
# ARM soft-float ABI with VFP (example for Cortex-A8)
make HOST_CC="gcc -m32" CROSS=arm-linux-gnueabi- \
TARGET_CFLAGS="-mcpu=cortex-a8 -mfloat-abi=softfp"
# ARM hard-float ABI with VFP (armhf, requires recent toolchain)
make HOST_CC="gcc -m32" CROSS=arm-linux-gnueabihf-
# PPC
make HOST_CC="gcc -m32" CROSS=powerpc-linux-gnu-
# PPC/e500v2 (fast interpreter only)
make HOST_CC="gcc -m32" CROSS=powerpc-e500v2-linux-gnuspe-
# MIPS big-endian
make HOST_CC="gcc -m32" CROSS=mips-linux-
# MIPS little-endian
make HOST_CC="gcc -m32" CROSS=mipsel-linux-
You can cross-compile for **Android** using the Android NDK. Adjust the environment variables to match your installation and desired target platform. For example, Android 4.1 corresponds to ABI level 16.
# Android/ARM, armeabi-v7a (ARMv7 VFP), Android 4.1+ (JB)
NDKDIR=/opt/android/ndk
NDKBIN=$NDKDIR/toolchains/llvm/prebuilt/linux-x86_64/bin
NDKCROSS=$NDKBIN/arm-linux-androideabi-
NDKCC=$NDKBIN/armv7a-linux-androideabi16-clang
make HOST_CC="gcc -m32" CROSS=$NDKCROSS \
STATIC_CC=$NDKCC DYNAMIC_CC="$NDKCC -fPIC" \
TARGET_LD=$NDKCC TARGET_AR="$NDKBIN/llvm-ar rcus" \
TARGET_STRIP=$NDKBIN/llvm-strip
Please use the LuaJIT 2.1 branch to compile for **iOS** (iPhone/iPad).
Cross-compiling for Consoles
Building LuaJIT for consoles requires a host compiler (x86 or x64) that supports building for the console and a cross-compiler from the official console SDK.
Due to console restrictions, the JIT compiler is disabled and only the fast interpreter is built. This is still faster than plain Lua, but much slower than the JIT compiler. FFI is also disabled as it's not very useful in such environments.
The following command builds a static library libluajit.a that can be linked into your game like the Lua library.
To cross-compile for **PS3** from a Linux host (requires 32-bit GCC, i.e. multilib Linux/x64) or a Windows host (requires 32-bit MinGW), run:
make HOST_CC="gcc -m32" CROSS=ppu-lv2-
To cross-compile for other consoles from a Windows host, open the "Native Tools Command Prompt for VS". You need to select either 32-bit or 64-bit host compiler to match the target. Then cd to the src directory where you've unpacked the source code and run the build command given in the table:
| Console | Bits | Build Command |
|---|---|---|
| PS4 | 64 | ps4build |
| PS Vita | 32 | psvitabuild |
| Xbox 360 | 32 | xedkbuild |
Check the comments in the respective *.bat files for more options.
Embedding LuaJIT
LuaJIT is compatible with the Lua 5.1 API. If you've already embedded Lua into your application, you probably don't need to do anything to switch to LuaJIT, except link to a different library:
- It's strongly recommended to build LuaJIT separately using the provided build system. Please don't try to integrate individual source files into your build tree. You're likely to mess up internal build dependencies or compiler flags. Treat LuaJIT like any other external library and link your application with the dynamic library or static library as needed.
- If you want to use
require()to load C modules compiled for plain Lua, you need to ensure public symbols (e.g.lua_pushnumber) are also exported:- On POSIX systems, you can link to the shared libray or link the static library into your application. In the latter case, you need to export all public symbols from the main executable (e.g.
-Wl,-Eon Linux) and add external dependencies (e.g.-lm -ldlon Linux). - Since Windows symbols are bound to specific DLL names, you need to link to the lua51.dll built by LuaJIT (don't rename the DLL). You can only statically link LuaJIT on Windows if you don't intend to load Lua/C modules at runtime.
- On POSIX systems, you can link to the shared libray or link the static library into your application. In the latter case, you need to export all public symbols from the main executable (e.g.
Additional tips for using C API functions to initialize LuaJIT:
- Here's a simple example of embedding Lua or LuaJIT into an application.
- Make sure to use
luaL_newstate. Avoid usinglua_newstateas it uses the system's (slower) default memory allocator (this is not supported on 64-bit architectures). - Make sure to use
luaL_openlibsinstead of the old Lua 5.0 style of directly callingluaopen_baseetc. - To change or extend the list of standard libraries to be loaded, copy
src/lib_init.cto your project and modify it accordingly. Make sure thejitlibrary is loaded, otherwise the JIT compiler won't be activated. - The
bit.*module for bitwise operations is already built-in. No need to statically link the Lua BitOp to your application.
Tips for Distribution Maintainers
The LuaJIT build system provides extra provisions for the needs of most POSIX-based distributions. If you're a package maintainer for a distribution, *please* make use of these features and avoid patching, subverting, automating or messing with the build system in incomprehensible ways.
There's absolutely no need to patch luaconf.h or any Makefile. And please don't manually pick files for your package—just use whatever files make install creates. *All files and directories* it creates are there for a reason.
The build system uses GNU make and automatically detects most settings based on where you build it. This should work for native builds even in a sandbox. You may need to pass some of the following flags to the make and make install command lines for regular distribution builds:
PREFIXoverrides the installation path, usually should be set to/usr. Setting this also changes the module path and paths needed to find shared libraries.DESTDIRis an absolute path that allows you to install to a shadow tree instead of the build system's root tree.MULTILIBsets the architecture-specific library path component for multi-lib systems. The default islib.- Check the top-level
Makefileandsrc/Makefilefor other variables to adjust. The following variables *may* be overridden, but *are not* recommended unless special needs like cross-compilation:BUILDMODE, CC, HOST_CC, STATIC_CC, DYNAMIC_CC, CFLAGS, HOST_CFLAGS, TARGET_CFLAGS, LDFLAGS, HOST_LDFLAGS, TARGET_LDFLAGS, TARGET_SHLDFLAGS, TARGET_FLAGS, LIBS, HOST_LIBS, TARGET_LIBS, CROSS, HOST_SYS, TARGET_SYS
The build system has a special target for amalgamated builds, make amalg. This compiles the LuaJIT core into one huge C file and allows GCC to generate faster, shorter code. Alas, this requires a lot of memory during the build process. This might be a problem for some users, which is why it's not enabled by default. But for most build farms this shouldn't be an issue. It's recommended that binary distributions use this target in their LuaJIT builds.
The tl;dr version of the above:
make amalg PREFIX=/usr && \
make install PREFIX=/usr DESTDIR=/tmp/buildroot
Finally, if you encounter any difficulties, please contact me first rather than releasing broken packages to unsuspecting users. Because anyway, they usually complain to me (upstream) rather than you (package maintainer).
Running LuaJIT
LuaJIT has a single standalone executable file, called luajit on POSIX systems and luajit.exe on Windows. It can be used to run simple Lua statements or entire Lua applications from the command line. It also has an interactive mode.
Command-line Options
The luajit standalone executable is just a slightly modified version of the regular lua standalone executable. It also supports the same basic options. luajit -h prints a short list of available options. For details, please check the Lua manual.
LuaJIT has some additional options:
-b[options] input output
This option saves or lists bytecode. The following additional options are accepted:
-l— List bytecode only.-s— Strip debug info (this is the default).-g— Keep debug info.-n name— Set module name (default: auto-detected from input name).-t type— Set output file type (default: auto-detected from output name).-a arch— Override object file architecture (default: native).-o os— Override target file OS (default: native).-e chunk— Use chunk string as input.-(single dash) — Use stdin as enput and/or stdout as output.
The output file type is auto-detected based on the output filename's extension:
c— C source file, exported bytecode data.h— C header file, static bytecode data.objoro— Object file, exported bytecode data (OS and architecture specific).rawor any other extension — Raw bytecode file (portable).
Notes:
- For information on bytecode portability and compatibility, see also
string.dump(). - Files in raw bytecode format are auto-detected and can be loaded like any Lua source file. For example, directly from the command line or using
loadfile(),dofile()etc. - To statically embed a module's bytecode into your application, generate an object file and link it with your application.
- On most ELF-based systems (e.g. Linux), you need to explicitly export global symbols when linking your application, e.g.:
-Wl,-E require()tries to load embedded bytecode data from exported symbols (in*.exeorlua51.dllon Windows) and from shared libraries inpackage.cpath.
Typical usage examples:
luajit -b test.lua test.out # Save bytecode to test.out
luajit -bg test.lua test.out # Save with debug info
luajit -be "print('hello world')" test.out # Save cmdline script
luajit -bl test.lua # List to stdout
luajit -bl test.lua test.txt # List to test.txt
luajit -ble "print('hello world')" # List cmdline script
luajit -b test.lua test.obj # Generate object file
# Link test.obj with your application and load it with require("test")
-j cmd[=arg[,arg...]]
This option executes a LuaJIT control command or activates one of the loadable extension modules. The command is first looked up in the jit.* library. If no matching function is found, the module named jit.<cmd> is loaded and its start() function is called with the specified arguments (if any). The space between -j and cmd is optional.
The following LuaJIT control commands are available:
-jon— Turn on the JIT compiler (default).-joff— Turn off the JIT compiler (interpreter only).-jflush— Flush the entire cache of compiled code.-jv— Show detailed information about JIT compiler progress.-jdump— Dump code and structures used at various compiler stages.
The -jv and -jdump commands are extension modules written in Lua. They're mainly used for debugging the JIT compiler itself. For descriptions of their options and output format, read the comment blocks at the beginning of the source code. They can be found in the lib directory of the source distribution or installed under the jit directory. By default, this is /usr/local/share/luajit-XX.YY.ZZ/jit on POSIX systems (replace XX.YY.ZZ with the installed version).
-O[level]
-O[+]flag
-O-flag
-Oparam=value
This option allows fine-grained control over optimizations used by the JIT compiler. This is mainly for debugging LuaJIT itself. Note that the JIT compiler is very fast (we're talking microseconds to milliseconds). Disabling optimizations has no noticeable effect on its overhead, but usually generates slower running code.
The first form sets an optimization level—this makes specific combinations of optimization flags possible. -O0 turns off all optimizations, higher numbers mean more optimizations. Omitting the level (i.e. just -O) sets the default optimization level, which is -O3 in the current version.
The second form adds or removes individual optimization flags. The third form sets VM or JIT compiler parameters to specific values.
You can use this option multiple times (like -Ocse -O-dce -Ohotloop=10) or use commas to separate multiple settings (like -O+cse,-dce,hotloop=10). These settings are applied from left to right, later settings override earlier ones. You can freely mix these three forms, but note that setting an optimization level overrides all earlier flags.
The following flags and the optimization levels that enable them are available:
| Flag | -O1 | -O2 | -O3 | |
|---|---|---|---|---|
| fold | • | • | • | Constant folding, simplification and reassociation |
| cse | • | • | • | Common subexpression elimination |
| dce | • | • | • | Dead code elimination |
| narrow | • | • | Narrow numbers to integers | |
| loop | • | • | Loop optimizations (code hoisting) | |
| fwd | • | Load forwarding (L2L) and store forwarding (S2L) | ||
| dse | • | Dead store elimination | ||
| abc | • | Array bounds check elimination | ||
| sink | • | Allocation/store sinking | ||
| fuse | • | Fuse operands into instructions |
The following parameters and their default settings:
| Parameter | Default | |
|---|---|---|
| maxtrace | 1000 | Maximum number of traces in cache |
| maxrecord | 4000 | Maximum number of recorded IR instructions |
| maxirconst | 500 | Maximum number of IR constants in a trace |
| maxside | 100 | Maximum number of side traces of a root trace |
| maxsnap | 500 | Maximum number of snapshots in a trace |
| hotloop | 56 | Iterations to detect hot loop or hot call |
| hotexit | 10 | Exits to start side tracing |
| cside | 4 | Attempts to compile side trace |
| instunroll | 4 | Maximum unroll factor for unstable loops |
| loopunroll | 15 | Maximum unroll factor for loop ops in side traces |
| callunroll | 3 | Maximum unroll factor for pseudo-recursive calls |
| recunroll | 2 | Minimum unroll factor for real recursion |
| sizemcode | 32 | Size of each machine code area (in KBytes) (Windows: 64K) |
| maxmcode | 512 | Maximum total size of all machine code areas, in KBytes |