bun:ffi 模块高效地从 JavaScript 调用原生库。它适用于任何支持 C ABI 的语言,包括 Zig、Rust、C/C++、C#、Nim 和 Kotlin。
dlopen 用法(bun:ffi)
打印 sqlite3 的版本号:
性能
根据我们的基准测试,bun:ffi 的速度大约是 Node.js 通过 Node-API 进行 FFI 的 2-6 倍。
Bun 生成并即时编译 C 绑定,高效地在 JavaScript 类型和原生类型之间转换值。为了编译 C,Bun 嵌入了 TinyCC,一个小型且快速的 C 编译器。
用法
Zig
add.zig
terminal
dlopen:
Rust
C++
FFI 类型
支持以下FFIType 值。
buffer 参数必须是 TypedArray 或 DataView。
字符串
JavaScript 字符串和类 C 字符串是不同的,这给使用字符串与原生库交互带来了复杂性。JavaScript 字符串和 C 字符串有何不同?
JavaScript 字符串和 C 字符串有何不同?
JavaScript 字符串:
- UTF16(每个字母 2 字节)或可能的 latin1,取决于 JavaScript 引擎和使用的是什么字符
length单独存储- 不可变
- UTF8(每个字母 1 字节),通常
- 不存储长度。相反,字符串以 null 结尾:其长度是第一个
\0的索引 - 可变
bun:ffi 导出了 CString,它扩展了 JavaScript 内置的 String 以支持 null 结尾的字符串并添加了一些额外功能:
new CString() 构造器会克隆 C 字符串,因此在 ptr 被释放后继续使用 myString 是安全的。
returns 时,FFIType.cstring 将指针强制转换为 JavaScript string。当用于 args 时,FFIType.cstring 与 ptr 相同。
函数指针
不支持异步函数
CFunction,例如配合您从已加载的 Node-API(napi)模块获得的指针。
linkSymbols:
回调
使用JSCallback 创建可传递给 C/FFI 函数的 JavaScript 回调函数,使原生代码可以回调您的 JavaScript 或 TypeScript。这对于异步代码非常有用。
JSCallback 的使用后,调用 close() 以释放内存。
实验性线程安全回调
JSCallback 具有实验性的线程安全回调支持。如果您将回调函数传递到创建它的线程之外的其他线程,则需要此功能。通过可选的 threadsafe 参数启用它。
线程安全回调在从运行 JavaScript 代码的另一个线程(即 Worker)调用时效果最佳。未来的 Bun 版本将支持从任何线程调用它们,例如由 Bun 不知晓的原生库生成的新线程。
⚡️ 性能提示:为获得轻微的性能提升,直接传递
JSCallback.prototype.ptr 而不是 JSCallback 对象:指针
Bun 将指针表示为 JavaScript 中的number。
64 位指针如何适合 JavaScript 数值?
64 位指针如何适合 JavaScript 数值?
64 位处理器支持多达 52 位的可寻址空间。JavaScript 数值支持 53 位的可用空间,这留下了约 11 位的额外空间。为什么不用
BigInt? BigInt 更慢。JavaScript 引擎单独分配 BigInt,因此它们不能放入常规的 JavaScript 值中。如果您将 BigInt 传递给函数,它会被转换为 number。Windows 注意:Windows API 类型 HANDLE 不表示虚拟地址,将其用于 ptr 不会按预期工作。请使用 u64 安全地表示 HANDLE 值。TypedArray 转换为指针:
ArrayBuffer:
DataView:
read:
read 函数的行为类似于 DataView,但通常更快,因为它不需要创建 DataView 或 ArrayBuffer。
内存管理
bun:ffi 不会为您管理内存。当您使用完内存后,必须自行释放。
从 JavaScript
要跟踪TypedArray 何时不再从 JavaScript 使用,请使用 FinalizationRegistry。
从 C、Rust、Zig 等
要跟踪TypedArray 何时不再从 C 或 FFI 使用,请向 toArrayBuffer 或 toBuffer 传递一个回调和可选上下文的指针。回调会在垃圾收集器释放底层 ArrayBuffer JavaScript 对象时稍后调用。
期望的签名与 JavaScriptCore 的 C API 相同:
内存安全
不要在 FFI 之外使用原始指针。未来的 Bun 版本可能会添加 CLI 标志来禁用bun:ffi。
指针对齐
如果 API 期望的指针大小不是char 或 u8,请确保 TypedArray 也是该大小。由于对齐原因,u64* 与 [8]u8* 并不完全相同。
传递指针
在 FFI 函数期望指针的地方,传递同等大小的TypedArray:
TypedArray 转换为指针。
硬核模式
硬核模式
如果您不想要自动转换,或者想要指向
TypedArray 内特定字节偏移量的指针,请直接获取 TypedArray 的指针: