LuaJIT and the FFI
35.1 About LuaJIT
LuaJIT (by Mike Pall) is a tracing JIT compiler for Lua 5.1 (with some 5.2 extensions). It's extremely fast and often comparable to C for numeric code.
It's used by OpenResty, Kong, Neovim, LÖVE, Snabb, and game engines.
Compatibility: Lua 5.1 syntax/semantics (no integers, goto supported, // and native bitwise operators not supported; use the bit library). Development continues on the v2.1 rolling branch (there are no formal releases).
35.2 The FFI: Call C Directly from Lua
local ffi = require("ffi")
ffi.cdef[[
int printf(const char *fmt, ...);
size_t strlen(const char *s);
typedef struct { double x, y; } point_t;
double sqrt(double x);
]]
ffi.C.printf("Hello %s from %d\n", "FFI", 2025)
print(ffi.C.strlen("LuaJIT"))
-- C structs and arrays (fast, compact)
local p = ffi.new("point_t", 3, 4)
print(ffi.C.sqrt(p.x * p.x + p.y * p.y)) --> 5
local arr = ffi.new("double[?]", 1000000) -- 8 MB native array, much faster than tables for numeric work
for i = 0, 999999 do arr[i] = i * 0.5 end -- 0-based!
-- Metatypes: methods on C types
local Point = ffi.metatype("point_t", {
__index = { length = function(self) return math.sqrt(self.x ^ 2 + self.y ^ 2) end },
__add = function(a, b) return ffi.new("point_t", a.x + b.x, a.y + b.y) end,
__tostring = function(self) return ("(%g, %g)"):format(self.x, self.y) end,
})
local q = Point(1, 2) + Point(3, 4)
print(tostring(q), q:length())
-- Load other shared libraries
local zlib = ffi.load(ffi.os == "Windows" and "zlib1" or "z")
ffi.cdef[[ unsigned long compressBound(unsigned long sourceLen); ]]
print(zlib.compressBound(1000))
-- Memory management
local buf = ffi.gc(ffi.C.m
…35.3 LuaJIT Performance Tips
Write JIT-friendly code: avoid NYI ("not yet implemented") operations in hot loops (some string functions, pairs in older versions, varargs-heavy code). Check with -jv / -jdump: luajit -jv script.lua.
Use ffi arrays/structs for numeric data, cache globals and module functions in locals, and avoid creating closures in hot loops.
Extras: bit.* (bitwise operations), jit.* (control the JIT), table.new/table.clear (via require "table.new"), string.buffer (2.1).