| 中文 | English |
FakeLua 是面向高性能宿主的可嵌入 Lua 子集运行时:脚本可编译为字节码由内置虚拟机执行,也可经 GCC/TCC JIT 生成原生机器码;并内置大量 C++ native 标准库(网络/HTTP/数据库/加密等),采用 Arena 内存池 + 帧重置,无 GC 停顿。
FakeLua 的设计初衷是为了在高性能游戏服务器或类似的实时系统中,解决传统脚本语言(如标准 Lua/LuaJIT)由于垃圾回收(GC)机制带来的吞吐量抖动和内存膨胀问题。
在典型的实时高性能服务器架构中:
为了配合上述定位,FakeLua 没有引入复杂的动态垃圾回收器(如三色标记、分代 GC),而是采用了极其高效的 Arena 内存池(Bump Allocator):
malloc 的碎片和多余开销。State::Reset()。它会逆序调用已创建对象的析构函数,但无需单独释放每块内存,而是将内存池的偏移指针直接重置为 0。没有复杂的对象图遍历,没有系统级的 free 耗时与内存碎片整理,清理操作瞬时完成。这种设计使得 FakeLua 在保持 JIT 原生执行速度的同时,能够彻底消除垃圾回收停顿(GC Pause)对帧率的影响,让内存开销保持在一条完全可预测的、极低的水平线上。
同一套 Call API 可切换任意已注册后端:
-O3)生成高质量原生代码,生产环境主力。src/interp/)。无需宿主 C 编译器,便于移植、工具链以及 JIT↔解释器混合闭包。int ret = 0;
Call(s, JIT_GCC, "add", ret, 10, 20); // 生产:GCC (-O3)
Call(s, JIT_TCC, "add", ret, 10, 20); // 开发/测试:TCC(极速编译)
Call(s, JIT_INTERP, "add", ret, 10, 20); // 字节码虚拟机(无需宿主 C 编译器)
编译器对函数的数学参数自动做类型推断与特化:
int64_t / double 组合),以及一个运行时入口分发器,根据实际参数类型路由到对应特化体。int64_t/double)计算,比较表达式也生成原生 C bool 而非走 CVar 装箱路径,彻底消除热路径上的类型判断开销。-- 示例 Lua 函数:递归计算 Fibonacci
function fib(n)
if n <= 1 then return n end
return fib(n - 1) + fib(n - 2)
end
编译器自动生成的特化 C 代码:
// 1. 数值参数特化体:形参/返回值直接提升为原生 int64_t,无需 CVar 装箱与运行时类型判断
static int64_t fib_spec_0(int64_t n) {
if (n <= 1) {
return n;
}
return fib_spec_0(n - 1) + fib_spec_0(n - 2);
}
// 2. 通用入口分发器:快速判断传入类型,零开销路由到原生 C 特化函数
static CVar fib_dispatcher(CVar n_var) {
if (LIKELY(n_var.type_ == VAR_INT)) {
return (CVar){.type_ = VAR_INT, .data_.i = fib_spec_0(n_var.data_.i)};
}
// ... 动态路由至 double 特化体或通用 CVar 分支
}
以递归 Fibonacci(n=32)为例,GCC 后端比 Lua 5.4 快 36.6x,TCC 后端快 11.2x(详见 benchmark/README.zh.md / English)。
如果 Table 构造函数在编译期可以静态推断出其所有 Key(如字符串字面量、显式/隐式整型索引、布尔型、浮点型),编译器会将其特化为 C 语言结构体:
FL_SPEC/FL_SET_SPEC)进行极速读写,彻底避免了哈希查找与键值对比。spec_get / spec_set 专有函数指针进行回调查找。-- 示例 Lua 代码:定义与读写 Table 字段
local point = { x = 10, y = 20 }
point.x = point.x + 5
编译器自动生成的特化 C 结构体与指针偏移访问代码:
// 1. 编译期推断 Key 布局,自动生成 C 结构体定义
typedef struct Table_Spec_1 {
CVar x;
CVar y;
} Table_Spec_1;
// 2. 初始化 Table 时绑定专有 struct 布局与 spec 读写句柄
SET_TABLE_SPEC(point, Table_Spec_1, spec_get_fn, spec_set_fn, 2);
FL_SET_SPEC(Table_Spec_1, point, x, 0, (CVar){.type_ = VAR_INT, .data_.i = 10});
FL_SET_SPEC(Table_Spec_1, point, y, 1, (CVar){.type_ = VAR_INT, .data_.i = 20});
// 3. 字段读写转换为极速指针成员偏移(彻底免除哈希表查找开销)
FL_SPEC(Table_Spec_1, point, x) = NativeAdd(FL_SPEC(Table_Spec_1, point, x), (CVar){.type_ = VAR_INT, .data_.i = 5});
CVar *,同作用域多闭包共享同一堆指针。return a, b,C++ 侧通过 std::tie(a, b, c) 接收。vararg 函数 ... 完整支持。function(args) body end 作为值传递,支持任意 Callee 调用如 tbl[key]()。obj:method(args) 语法糖,自动将调用者作为 self 参数传递。for in 迭代器:支持无状态迭代器和闭包生成器,pairs/ipairs 保留原生 C 结构体极速循环。package "Name" 命名空间隔离,零 require 跨模块互调。__fakelua_init() 中执行。RegisterMethod 绑定、冒号语法调用。string.find/match/gmatch/gsub 使用自包含的 Lua 模式引擎(%d/%w 字符类、自定义集合、惰性 -、捕获、前沿 %f[set]、平衡 %bxy),与标准 Lua 完全兼容。string.trim/trim_left/trim_right/split/join/replace/starts_with/ends_with/contains/iequals/icontains/istarts_with/iends_with 底层使用 Boost.Algorithm。coroutine.create/resume/yield。__index、__newindex 等元方法。require/module:无标准模块系统(由 package "Name" 机制替代)。rawequal/rawget/rawset/rawlen:因无元表,这些函数无意义。debug.*。"10" + 1 会报错)。FakeLua 在 src/native/ 下提供 30+ 个独立 C++ 原生模块(每个 State 创建时自动注册),覆盖数学、字符串、表、IO、网络、定时器、事件、随机数、容器、压缩、加密、序列化、数据库、Protobuf、配置解析、日志、子进程等领域。
完整 API 文档: src/native/README.zh.md / English
| 分类 | 模块 |
|---|---|
| 核心 Lua | basic、math、table、string、os、utf8、io、random |
| 运行时 / IO | runtime(runtime.tick())、net(TCP/UDP)、http(HTTP/1.1)、url、timer、event |
| 数据 | json、csv、serialize、protobuf、container(Boost.Container deque/vector/list/map/set) |
| 配置解析 | yaml、toml、xml、ini |
| 数据库 | mysql(异步 + 连接池)、redis(异步)、sqlite(同步) |
| 加解密 / 压缩 | compress(LZ4/zlib/gzip/Zstd)、crypto(OpenSSL 摘要/对称加密、UUID、CRC-32、xxHash) |
| 进程 | process(process.run;不替换 os.execute) |
| 日志 | log(级别、分类标签输出、文件滚动) |
| 对象 | object(NativeObject Lua 侧 API) |
string.find/match/gmatch/gsub使用 Lua 5.4 模式(自包含字节模式引擎,位于src/native/string/lua_pattern.*),不是 ECMAScript/POSIX 正则。
string.find/match/gmatch/gsub 严格遵循 PUC-Rio Lua 5.4 语义,包括:
%. %( %) %% %+ 等;. 匹配任意单字节。%a %c %d %g %l %p %s %u %w %x,大写取反;%z 匹配零字节。[set]、[^set]、[a-z]、集合内嵌字符类([%d_])、开头的 ]/- 按字面量处理。* + - ?,含 Lua 独有的惰性 -(a.-b)。^ 与末尾的 $。(...)、位置捕获 ()、模式内反向引用 %1…,gsub 替换串 %0…%9 与 %%。%f[set] 与平衡匹配 %bxy。nil/false 时保留原匹配;find 的 plain=true 跳过模式引擎。pcall 捕获),而不是静默返回不匹配。string.match("limit=15", "%d+") --> "15"
string.gsub("hello world", "(%w+) (%w+)", "%2 %1") --> "world hello", 1
string.match("a(b(c)d)e", "%b()") --> "(b(c)d)"
Lua 模式不是正则:没有分支交替(
a|b),转义前缀是%而非\。为旧 ECMAScript 行为写的脚本(如"\\d+"、$1替换)需改写为 Lua 写法("%d+"、"%1")。
cmake -S . -B build
cmake --build build --parallel
macOS 需先
brew install lua cmake,并在 cmake 时加-DCMAKE_PREFIX_PATH="$(brew --prefix)"。
仅构建核心库与命令行工具(不含测试/基准):
cmake --build build --target fakelua flua --parallel
cmake -S . -B build -G Ninja
cmake --build build --parallel
ctest --test-dir build -V
cmake -S . -B build -DCMAKE_EXPORT_COMPILE_COMMANDS=ON
cmake --build build --parallel
ctest --test-dir build -V
./build/bin/bench_mark
单元测试与 benchmark 依赖 Lua 开发包(头文件
lua.h和库文件)。
- 在 Linux 上:
sudo apt-get install liblua5.4-dev或liblua5.3-dev- 在 macOS 上:
brew install lua- 在 Windows MSYS2 上:
pacman -S mingw-w64-x86_64-lua
flua./build/bin/flua <script.lua> --entry=<func> --jit_type=<0|1|2> --repeat=<N>
--entry:入口函数名(默认 main)--jit_type:0=TCC,1=GCC,2=INTERP(字节码虚拟机)--repeat:重复调用次数(用于性能测量)--debug:是否启用调试模式(默认 false,若为 true 则输出生成的 C 源码 / 更详细诊断)# 编译
cmake -S . -B build
cmake --build build --parallel
# 安装(默认前缀:/usr/local)
sudo cmake --install build
# 或:cd build && sudo make install
安装到系统后,其他 CMake 项目可以通过标准的 find_package 引入并链接 FakeLua:
cmake_minimum_required(VERSION 3.20)
project(my_project CXX)
set(CMAKE_CXX_STANDARD 23)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
# 查找 FakeLua
find_package(fakelua REQUIRED)
add_executable(my_project main.cpp)
# 链接 fakelua(自动引入头文件路径和链接参数)
target_link_libraries(my_project PRIVATE fakelua::fakelua)
# 同时兼容不带命名空间的别名写法:
# target_link_libraries(my_project PRIVATE fakelua)
在 C++ 代码中引用头文件:
#include "fakelua.h"
// 或者使用带目录前缀的形式:
// #include <fakelua/fakelua.h>
FakeLua 还会同时安装 fakelua.pc,支持通过 pkg-config 使用。
对比 Lua 5.4、FakeLua TCC、FakeLua GCC,覆盖 Fibonacci、GCD、快速幂、线性求和、冒泡排序、筛质数等 11 类算法(Release -O3 模式):
| 算法(典型参数) | Lua 5.4 | FakeLua TCC | FakeLua GCC |
|---|---|---|---|
| Fibonacci n=32 | 297.9 ms | 26.7 ms(11.2x↑) | 6.8 ms(36.6x↑) |
| Sum n=5000000 | 33.9 ms | 18.4 ms(1.8x↑) | 1.1 ms(30.4x↑) |
| Popcount n=100000 | 18.2 ms | 3.1 ms(5.9x↑) | 488.0 μs(37.3x↑) |
| BubbleSort n=200 | 1.5 ms | 3.3 ms(0.45x) | 738.8 μs(1.9x↑) |
| Sieve n=5000 | 353.4 μs | 1.0 ms(0.34x) | 219.3 μs(1.8x↑) |
| FloatPoly n=1000000 | — | — | 34.9x↑(浮点特化,GCC 2x 快于 C++) |
TCC 纯计算类场景普遍快于 Lua;在包含 Table 操作的场景下,Table 结构体特化使 GCC 与 TCC 的 Table 读写性能均大幅提升。完整数据见 benchmark/README.zh.md / English。
FakeluaStateGuard guard;
State* s = guard.GetState();
CompileFile(s, "script.lua", CompileConfig{.debug_mode = false});
int sum = 0;
Call(s, JIT_GCC, "add", sum, 10, 20); // 嵌入调用 Lua 函数
// 手动管理(不推荐,容易泄漏)
State* s = FakeluaNewState(StateConfig{});
// ... 使用 s ...
FakeluaDeleteState(s);
// 或使用 RAII 风格(推荐)
FakeluaStateGuard guard(StateConfig{});
State* s = guard.GetState();
// ... 使用 s ...
// 自动释放
| 函数 | 功能 |
|---|---|
FakeluaNewState() |
创建 FakeLua 状态 |
FakeluaDeleteState() |
释放 FakeLua 状态 |
CompileFile() |
编译 Lua 文件 |
CompileString() |
编译 Lua 代码字符串 |
Call() |
调用编译后的函数 |
GetLastRecordedCCode() |
获取最近编译的 C 代码 |
SetVarInterfaceNewFunc() |
设置自定义 VarInterface 工厂 |
SetDebugLogLevel(s, level) |
设置本 State 的调试日志级别(0=Trace … 6=Off;Lua 侧用 log.set_level) |
// 原生 → FakeLua
CVar v_int = inter::NativeToFakelua(s, 42);
CVar v_str = inter::NativeToFakelua(s, std::string("hello"));
// FakeLua → 原生
int native_int = inter::FakeluaToNative<int>(v_int);
std::string native_str = inter::FakeluaToNative<std::string>(v_str);
class CustomVar : public VarInterface { /* ... */ };
SetVarInterfaceNewFunc(s, []() { return new CustomVar(); });
// Call 中传递的 table 类型参数会自动构造为 CustomVar 实例
Lua 源码
↓
[词法分析] → tokens (flexer)
↓
[语法分析] → AST (bison + syntax_tree)
↓
[文件级语句校验] → 拒绝非声明语句 (semantic_analysis)
↓
[预处理] → normalized AST (preprocessor)
↓
[语义分析] → analysis result (semantic_analysis)
↓
[类型推导] → type hints (type_inferencer)
↓
┌─────────────────────────────┬──────────────────────────────┐
↓ ↓ ↓
[C 代码生成] [字节码生成] (共享 AST)
(c_gen) (interp/codegen)
↓ ↓
[JIT TCC / GCC] [解释器虚拟机]
原生机器码 (interp/interpreter)
└───────────── Call(s, JIT_*, …) ─────────────┘
| 模块 | 职责 |
|---|---|
lexer/parser |
Lua 词法和语法解析 |
syntax_tree |
AST 表示和遍历 |
preprocessor |
Lua 语法规范化(如 functiondef 提升) |
semantic_analysis |
语义和控制流分析 |
type_inferencer |
静态类型推导和 specialization 决策 |
c_gen |
C 代码生成和类型驱动优化 |
interp/* |
字节码生成、指令集与解释器虚拟机 |
compile_common |
公共类型推导和代码生成工具 |
jit/* |
TCC/GCC 后端与 Vm 函数注册表 |
native/* |
内置标准库(net、http、db、crypto 等) |
state |
FakeLua 运行时状态管理 |
var |
动态值 CVar 和转换工具 |
A: 完整 Lua 的某些动态特性(如 metatable)很难高效编译。子集实现聚焦于可静态分析的常见模式,通过类型推导和 JIT 编译获得接近 C 的性能。
A: GCC 是生产环境主力(-O3)。TCC 编译极快,适合开发与 CI。INTERP 跑字节码、无需宿主 C 编译器,适合受限环境、工具链与语义校验;热路径仍可与 JIT 闭包混合调用。
A: 可以——用 JIT_INTERP(运行时不依赖 GCC/TCC)或体积很小的 TCC 后端。OpenSSL/MySQL 等 native 依赖可按构建需求裁剪。
A: 启用 CompileConfig::debug_mode 查看日志和 C 代码;使用 GetLastRecordedCCode() 导出 C 代码进行分析。
A: 每个 State 当前为线程本地对象,多线程环境中应为每个线程创建独立的 State。