mirror of
https://github.com/bunkerity/bunkerweb
synced 2026-05-24 09:28:37 +00:00
e598aeb7 bugfix: Update s390x support. 8009e8cb Merge upstream to v2.1-agentzh 4c2a5331 tests: only run with 1 core. 52e83c8b tests: fix one test cases. 58b44276 Merge branch 'v2.1' into v2.1-agentzh 41fb94de Add randomized register allocation for fuzz testing. 2f6c451c ARM64: Improve register allocation for integer IR_MUL/IR_MULOV. 7ff8f26e ARM64: Fix register allocation for IR_*LOAD. 356231ed Merge branch 'master' into v2.1 c6ee7e19 Update external MSDN URL in code. 83954100 FFI/ARM64/OSX: Handle non-standard OSX C calling conventions. cf903edb FFI: Unify stack setup for C calls in interpreter. 7cc53f0b ARM64: Prevent STP fusion for conditional code emitted by TBAR. 0fa2f1cb ARM64: Fix LDP/STP fusing for unaligned accesses. c0d5240a Merge branch 'master' into v2.1 0ef51b49 Handle table unsinking in the presence of IRFL_TAB_NOMM. 238a2a80 Merge branch 'master' into v2.1 6a3111a5 Use fallback name for install files without valid .git or .relver. a0b52aae Handle non-.git checkout with .relver in .bat-file builds. 631a45f7 Merge branch 'master' into v2.1 14e2917e Fix external C call stack check when using LUAJIT_MODE_WRAPCFUNC. 309fb42b Fix predict_next() in parser (again). 03c31124 Fix typo. ff192d13 Merge branch 'master' into v2.1 d0ce82ec Handle the case when .git is not a directory. 0b5bf71e Merge branch 'master' into v2.1 6a2163a6 Add .gitattributes to dynamically resolve .relver. 33e2a49d Add .gitattributes to dynamically resolve .relver. 093759d5 Fix for last commit: also remove symlink on uninstall. 748ab9d9 Switch to rolling releases: mark v2.1 as production. 54ef81f8 Merge branch 'master' into v2.1 ed21acd8 Fix Windows build scripts for rolling releases. 3c290f81 Merge branch 'master' into v2.1 6351abc7 Switch MSVC and console build scripts to rolling releases. 20908424 Merge branch 'master' into v2.1 50e0fa03 Switch build system to rolling releases. f0ff869b Merge branch 'master' into v2.1 c3459468 Update documentation for switch to rolling releases. ef587afb Merge branch 'master' into v2.1 158a284c Bump copyright date. cbb187ae Remove work-in-progress notice in string buffer docs. 72efc42e MIPS: Fix "bad FP FLOAD" assertion. 119fd1fa Ensure forward progress on trace exit to BC_ITERN. 27af72e6 ARM64: Add support for ARM64e pointer authentication codes (PAC). 117ddf35 DynASM/ARM64: Add instructions for ARM64e PAC. dbed79ea Merge branch 'master' into v2.1 abb27c77 Fix maxslots when recording BC_VARG, part 3. caf7cbc5 Fix predict_next() in parser. 9b544c25 MIPS32: Declare that the assembler part uses the FR=0 model. 93ce12ee ARM64: Fix assembly of HREFK (again). d5bbf9cd Fix frame for more types of on-trace error messages. 165ea18b Add workaround for bytecode dump of builtins. 91914b23 DynASM: Fix regression due to warning fix. 107baafb Merge branch 'v2.1' into v2.1-agentzh 8635cbab Merge branch 'master' into v2.1 aa2db7eb Fix base register coalescing in side trace. 8fbd576f ARM64: Fix assembly of HREFK. bd55d302 Merge branch 'master' into v2.1 a01cba9d Fix maxslots when recording BC_VARG, part 2. 0cc5fdfb Fix maxslots when recording BC_TSETM. 69dadad6 Merge branch 'master' into v2.1 94ada596 Fix maxslots when recording BC_VARG. b7a8c7c1 Fix register mask for stack check in head of side trace. 4c35a42d FFI: Fix ffi.metatype() for non-raw types. 9493acc1 ARM64: Fix LDP code generation. f9c31e34 PPC/e500 with SPE enabled: use soft float instead of failing. ff6c496b MIPSr6: Add missing files to Makefile install target. 51fb2f2c DynASM: Fix warnings. 2d8300c1 Fix frame for on-trace out-of-memory error. 8e53ccc6 Merge branch 'master' into v2.1 9f452bbe Fix handling of instable types in TNEW/TDUP load forwarding. 8c20c3b1 Fix compiler warning. 224129a8 Fix last commit. 1c279127 Print errors from __gc finalizers instead of rethrowing them. 8bbd58e5 Merge branch 'master' into v2.1 c7db8255 Fix TDUP load forwarding after table rehash. 96fc114a Fix canonicalization of +-0.0 keys for IR_NEWREF. 505e2c03 Merge branch 'master' into v2.1 8135de2a Improve error reporting on stack overflow. eccdf6d6 Merge branch 'master' into v2.1 126526ab Allow building sources with mixed LF/CRLF line-endings. d0e88930 Fix compiler warning. a4f4f5b8 Don't fail for Clang builds, which pretend to be an ancient GCC. git-subtree-dir: src/deps/src/luajit git-subtree-split: e598aeb7426dbc069f90ba70db9bce43cd573b0e
597 lines
22 KiB
HTML
597 lines
22 KiB
HTML
<!DOCTYPE html>
|
|
<html>
|
|
<head>
|
|
<title>FFI Tutorial</title>
|
|
<meta charset="utf-8">
|
|
<meta name="Copyright" content="Copyright (C) 2005-2023">
|
|
<meta name="Language" content="en">
|
|
<link rel="stylesheet" type="text/css" href="bluequad.css" media="screen">
|
|
<link rel="stylesheet" type="text/css" href="bluequad-print.css" media="print">
|
|
<style type="text/css">
|
|
table.idiomtable { font-size: 90%; line-height: 1.2; }
|
|
table.idiomtable tt { font-size: 100%; }
|
|
table.idiomtable td { vertical-align: top; }
|
|
tr.idiomhead td { font-weight: bold; }
|
|
td.idiomlua b { font-weight: normal; color: #2142bf; }
|
|
</style>
|
|
</head>
|
|
<body>
|
|
<div id="site">
|
|
<a href="https://luajit.org"><span>Lua<span id="logo">JIT</span></span></a>
|
|
</div>
|
|
<div id="head">
|
|
<h1>FFI Tutorial</h1>
|
|
</div>
|
|
<div id="nav">
|
|
<ul><li>
|
|
<a href="luajit.html">LuaJIT</a>
|
|
<ul><li>
|
|
<a href="https://luajit.org/download.html">Download <span class="ext">»</span></a>
|
|
</li><li>
|
|
<a href="install.html">Installation</a>
|
|
</li><li>
|
|
<a href="running.html">Running</a>
|
|
</li></ul>
|
|
</li><li>
|
|
<a href="extensions.html">Extensions</a>
|
|
<ul><li>
|
|
<a href="ext_ffi.html">FFI Library</a>
|
|
<ul><li>
|
|
<a class="current" href="ext_ffi_tutorial.html">FFI Tutorial</a>
|
|
</li><li>
|
|
<a href="ext_ffi_api.html">ffi.* API</a>
|
|
</li><li>
|
|
<a href="ext_ffi_semantics.html">FFI Semantics</a>
|
|
</li></ul>
|
|
</li><li>
|
|
<a href="ext_buffer.html">String Buffers</a>
|
|
</li><li>
|
|
<a href="ext_jit.html">jit.* Library</a>
|
|
</li><li>
|
|
<a href="ext_c_api.html">Lua/C API</a>
|
|
</li><li>
|
|
<a href="ext_profiler.html">Profiler</a>
|
|
</li></ul>
|
|
</li><li>
|
|
<a href="https://luajit.org/status.html">Status <span class="ext">»</span></a>
|
|
</li><li>
|
|
<a href="https://luajit.org/faq.html">FAQ <span class="ext">»</span></a>
|
|
</li><li>
|
|
<a href="https://luajit.org/list.html">Mailing List <span class="ext">»</span></a>
|
|
</li></ul>
|
|
</div>
|
|
<div id="main">
|
|
<p>
|
|
This page is intended to give you an overview of the features of the FFI
|
|
library by presenting a few use cases and guidelines.
|
|
</p>
|
|
<p>
|
|
This page makes no attempt to explain all of the FFI library, though.
|
|
You'll want to have a look at the <a href="ext_ffi_api.html">ffi.* API
|
|
function reference</a> and the <a href="ext_ffi_semantics.html">FFI
|
|
semantics</a> to learn more.
|
|
</p>
|
|
|
|
<h2 id="load">Loading the FFI Library</h2>
|
|
<p>
|
|
The FFI library is built into LuaJIT by default, but it's not loaded
|
|
and initialized by default. The suggested way to use the FFI library
|
|
is to add the following to the start of every Lua file that needs one
|
|
of its functions:
|
|
</p>
|
|
<pre class="code">
|
|
local ffi = require("ffi")
|
|
</pre>
|
|
<p>
|
|
Please note, this doesn't define an <tt>ffi</tt> variable in the table
|
|
of globals — you really need to use the local variable. The
|
|
<tt>require</tt> function ensures the library is only loaded once.
|
|
</p>
|
|
<p style="font-size: 8pt;">
|
|
Note: If you want to experiment with the FFI from the interactive prompt
|
|
of the command line executable, omit the <tt>local</tt>, as it doesn't
|
|
preserve local variables across lines.
|
|
</p>
|
|
|
|
<h2 id="sleep">Accessing Standard System Functions</h2>
|
|
<p>
|
|
The following code explains how to access standard system functions.
|
|
We slowly print two lines of dots by sleeping for 10 milliseconds
|
|
after each dot:
|
|
</p>
|
|
<pre class="code mark">
|
|
<span class="codemark">
|
|
①
|
|
|
|
|
|
|
|
|
|
|
|
②
|
|
③
|
|
④
|
|
|
|
|
|
|
|
⑤
|
|
|
|
|
|
|
|
|
|
|
|
⑥</span>local ffi = require("ffi")
|
|
ffi.cdef[[
|
|
<span style="color:#00a000;">void Sleep(int ms);
|
|
int poll(struct pollfd *fds, unsigned long nfds, int timeout);</span>
|
|
]]
|
|
|
|
local sleep
|
|
if ffi.os == "Windows" then
|
|
function sleep(s)
|
|
ffi.C.Sleep(s*1000)
|
|
end
|
|
else
|
|
function sleep(s)
|
|
ffi.C.poll(nil, 0, s*1000)
|
|
end
|
|
end
|
|
|
|
for i=1,160 do
|
|
io.write("."); io.flush()
|
|
sleep(0.01)
|
|
end
|
|
io.write("\n")
|
|
</pre>
|
|
<p>
|
|
Here's the step-by-step explanation:
|
|
</p>
|
|
<p>
|
|
<span class="mark">①</span> This defines the
|
|
C library functions we're going to use. The part inside the
|
|
double-brackets (in green) is just standard C syntax. You can
|
|
usually get this info from the C header files or the
|
|
documentation provided by each C library or C compiler.
|
|
</p>
|
|
<p>
|
|
<span class="mark">②</span> The difficulty we're
|
|
facing here, is that there are different standards to choose from.
|
|
Windows has a simple <tt>Sleep()</tt> function. On other systems there
|
|
are a variety of functions available to achieve sub-second sleeps, but
|
|
with no clear consensus. Thankfully <tt>poll()</tt> can be used for
|
|
this task, too, and it's present on most non-Windows systems. The
|
|
check for <tt>ffi.os</tt> makes sure we use the Windows-specific
|
|
function only on Windows systems.
|
|
</p>
|
|
<p>
|
|
<span class="mark">③</span> Here we're wrapping the
|
|
call to the C function in a Lua function. This isn't strictly
|
|
necessary, but it's helpful to deal with system-specific issues only
|
|
in one part of the code. The way we're wrapping it ensures the check
|
|
for the OS is only done during initialization and not for every call.
|
|
</p>
|
|
<p>
|
|
<span class="mark">④</span> A more subtle point is
|
|
that we defined our <tt>sleep()</tt> function (for the sake of this
|
|
example) as taking the number of seconds, but accepting fractional
|
|
seconds. Multiplying this by 1000 gets us milliseconds, but that still
|
|
leaves it a Lua number, which is a floating-point value. Alas, the
|
|
<tt>Sleep()</tt> function only accepts an integer value. Luckily for
|
|
us, the FFI library automatically performs the conversion when calling
|
|
the function (truncating the FP value towards zero, like in C).
|
|
</p>
|
|
<p style="font-size: 8pt;">
|
|
Some readers will notice that <tt>Sleep()</tt> is part of
|
|
<tt>KERNEL32.DLL</tt> and is also a <tt>stdcall</tt> function. So how
|
|
can this possibly work? The FFI library provides the <tt>ffi.C</tt>
|
|
default C library namespace, which allows calling functions from
|
|
the default set of libraries, like a C compiler would. Also, the
|
|
FFI library automatically detects <tt>stdcall</tt> functions, so you
|
|
don't need to declare them as such.
|
|
</p>
|
|
<p>
|
|
<span class="mark">⑤</span> The <tt>poll()</tt>
|
|
function takes a couple more arguments we're not going to use. You can
|
|
simply use <tt>nil</tt> to pass a <tt>NULL</tt> pointer and <tt>0</tt>
|
|
for the <tt>nfds</tt> parameter. Please note, that the
|
|
number <tt>0</tt> <em>does not convert to a pointer value</em>,
|
|
unlike in C++. You really have to pass pointers to pointer arguments
|
|
and numbers to number arguments.
|
|
</p>
|
|
<p style="font-size: 8pt;">
|
|
The page on <a href="ext_ffi_semantics.html">FFI semantics</a> has all
|
|
of the gory details about
|
|
<a href="ext_ffi_semantics.html#convert">conversions between Lua
|
|
objects and C types</a>. For the most part you don't have to deal
|
|
with this, as it's performed automatically and it's carefully designed
|
|
to bridge the semantic differences between Lua and C.
|
|
</p>
|
|
<p>
|
|
<span class="mark">⑥</span> Now that we have defined
|
|
our own <tt>sleep()</tt> function, we can just call it from plain Lua
|
|
code. That wasn't so bad, huh? Turning these boring animated dots into
|
|
a fascinating best-selling game is left as an exercise for the reader.
|
|
:-)
|
|
</p>
|
|
|
|
<h2 id="zlib">Accessing the zlib Compression Library</h2>
|
|
<p>
|
|
The following code shows how to access the <a
|
|
href="https://zlib.net/"><span class="ext">»</span> zlib</a> compression library from Lua code.
|
|
We'll define two convenience wrapper functions that take a string and
|
|
compress or uncompress it to another string:
|
|
</p>
|
|
<pre class="code mark">
|
|
<span class="codemark">
|
|
①
|
|
|
|
|
|
|
|
|
|
|
|
|
|
②
|
|
|
|
|
|
③
|
|
|
|
④
|
|
|
|
|
|
⑤
|
|
|
|
|
|
⑥
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
⑦</span>local ffi = require("ffi")
|
|
ffi.cdef[[
|
|
<span style="color:#00a000;">unsigned long compressBound(unsigned long sourceLen);
|
|
int compress2(uint8_t *dest, unsigned long *destLen,
|
|
const uint8_t *source, unsigned long sourceLen, int level);
|
|
int uncompress(uint8_t *dest, unsigned long *destLen,
|
|
const uint8_t *source, unsigned long sourceLen);</span>
|
|
]]
|
|
local zlib = ffi.load(ffi.os == "Windows" and "zlib1" or "z")
|
|
|
|
local function compress(txt)
|
|
local n = zlib.compressBound(#txt)
|
|
local buf = ffi.new("uint8_t[?]", n)
|
|
local buflen = ffi.new("unsigned long[1]", n)
|
|
local res = zlib.compress2(buf, buflen, txt, #txt, 9)
|
|
assert(res == 0)
|
|
return ffi.string(buf, buflen[0])
|
|
end
|
|
|
|
local function uncompress(comp, n)
|
|
local buf = ffi.new("uint8_t[?]", n)
|
|
local buflen = ffi.new("unsigned long[1]", n)
|
|
local res = zlib.uncompress(buf, buflen, comp, #comp)
|
|
assert(res == 0)
|
|
return ffi.string(buf, buflen[0])
|
|
end
|
|
|
|
-- Simple test code.
|
|
local txt = string.rep("abcd", 1000)
|
|
print("Uncompressed size: ", #txt)
|
|
local c = compress(txt)
|
|
print("Compressed size: ", #c)
|
|
local txt2 = uncompress(c, #txt)
|
|
assert(txt2 == txt)
|
|
</pre>
|
|
<p>
|
|
Here's the step-by-step explanation:
|
|
</p>
|
|
<p>
|
|
<span class="mark">①</span> This defines some of the
|
|
C functions provided by zlib. For the sake of this example, some
|
|
type indirections have been reduced and it uses the predefined
|
|
fixed-size integer types, while still adhering to the zlib API/ABI.
|
|
</p>
|
|
<p>
|
|
<span class="mark">②</span> This loads the zlib shared
|
|
library. On POSIX systems, it's named <tt>libz.so</tt> and usually
|
|
comes pre-installed. Since <tt>ffi.load()</tt> automatically adds any
|
|
missing standard prefixes/suffixes, we can simply load the
|
|
<tt>"z"</tt> library. On Windows it's named <tt>zlib1.dll</tt> and
|
|
you'll have to download it first from the
|
|
<a href="https://zlib.net/"><span class="ext">»</span> zlib site</a>. The check for
|
|
<tt>ffi.os</tt> makes sure we pass the right name to
|
|
<tt>ffi.load()</tt>.
|
|
</p>
|
|
<p>
|
|
<span class="mark">③</span> First, the maximum size of
|
|
the compression buffer is obtained by calling the
|
|
<tt>zlib.compressBound</tt> function with the length of the
|
|
uncompressed string. The next line allocates a byte buffer of this
|
|
size. The <tt>[?]</tt> in the type specification indicates a
|
|
variable-length array (VLA). The actual number of elements of this
|
|
array is given as the 2nd argument to <tt>ffi.new()</tt>.
|
|
</p>
|
|
<p>
|
|
<span class="mark">④</span> This may look strange at
|
|
first, but have a look at the declaration of the <tt>compress2</tt>
|
|
function from zlib: the destination length is defined as a pointer!
|
|
This is because you pass in the maximum buffer size and get back the
|
|
actual length that was used.
|
|
</p>
|
|
<p>
|
|
In C you'd pass in the address of a local variable
|
|
(<tt>&buflen</tt>). But since there's no address-of operator in
|
|
Lua, we'll just pass in a one-element array. Conveniently, it can be
|
|
initialized with the maximum buffer size in one step. Calling the
|
|
actual <tt>zlib.compress2</tt> function is then straightforward.
|
|
</p>
|
|
<p>
|
|
<span class="mark">⑤</span> We want to return the
|
|
compressed data as a Lua string, so we'll use <tt>ffi.string()</tt>.
|
|
It needs a pointer to the start of the data and the actual length. The
|
|
length has been returned in the <tt>buflen</tt> array, so we'll just
|
|
get it from there.
|
|
</p>
|
|
<p style="font-size: 8pt;">
|
|
Note that since the function returns now, the <tt>buf</tt> and
|
|
<tt>buflen</tt> variables will eventually be garbage collected. This
|
|
is fine, because <tt>ffi.string()</tt> has copied the contents to a
|
|
newly created (interned) Lua string. If you plan to call this function
|
|
lots of times, consider reusing the buffers and/or handing back the
|
|
results in buffers instead of strings. This will reduce the overhead
|
|
for garbage collection and string interning.
|
|
</p>
|
|
<p>
|
|
<span class="mark">⑥</span> The <tt>uncompress</tt>
|
|
functions does the exact opposite of the <tt>compress</tt> function.
|
|
The compressed data doesn't include the size of the original string,
|
|
so this needs to be passed in. Otherwise, no surprises here.
|
|
</p>
|
|
<p>
|
|
<span class="mark">⑦</span> The code, that makes use
|
|
of the functions we just defined, is just plain Lua code. It doesn't
|
|
need to know anything about the LuaJIT FFI — the convenience
|
|
wrapper functions completely hide it.
|
|
</p>
|
|
<p>
|
|
One major advantage of the LuaJIT FFI is that you are now able to
|
|
write those wrappers <em>in Lua</em>. And at a fraction of the time it
|
|
would cost you to create an extra C module using the Lua/C API.
|
|
Many of the simpler C functions can probably be used directly
|
|
from your Lua code, without any wrappers.
|
|
</p>
|
|
<p style="font-size: 8pt;">
|
|
Side note: the zlib API uses the <tt>long</tt> type for passing
|
|
lengths and sizes around. But all those zlib functions actually only
|
|
deal with 32 bit values. This is an unfortunate choice for a
|
|
public API, but may be explained by zlib's history — we'll just
|
|
have to deal with it.
|
|
</p>
|
|
<p style="font-size: 8pt;">
|
|
First, you should know that a <tt>long</tt> is a 64 bit type e.g.
|
|
on POSIX/x64 systems, but a 32 bit type on Windows/x64 and on
|
|
32 bit systems. Thus a <tt>long</tt> result can be either a plain
|
|
Lua number or a boxed 64 bit integer cdata object, depending on
|
|
the target system.
|
|
</p>
|
|
<p style="font-size: 8pt;">
|
|
Ok, so the <tt>ffi.*</tt> functions generally accept cdata objects
|
|
wherever you'd want to use a number. That's why we get a away with
|
|
passing <tt>n</tt> to <tt>ffi.string()</tt> above. But other Lua
|
|
library functions or modules don't know how to deal with this. So for
|
|
maximum portability, one needs to use <tt>tonumber()</tt> on returned
|
|
<tt>long</tt> results before passing them on. Otherwise the
|
|
application might work on some systems, but would fail in a POSIX/x64
|
|
environment.
|
|
</p>
|
|
|
|
<h2 id="metatype">Defining Metamethods for a C Type</h2>
|
|
<p>
|
|
The following code explains how to define metamethods for a C type.
|
|
We define a simple point type and add some operations to it:
|
|
</p>
|
|
<pre class="code mark">
|
|
<span class="codemark">
|
|
①
|
|
|
|
|
|
|
|
②
|
|
|
|
③
|
|
|
|
④
|
|
|
|
|
|
|
|
⑤
|
|
|
|
⑥</span>local ffi = require("ffi")
|
|
ffi.cdef[[
|
|
<span style="color:#00a000;">typedef struct { double x, y; } point_t;</span>
|
|
]]
|
|
|
|
local point
|
|
local mt = {
|
|
__add = function(a, b) return point(a.x+b.x, a.y+b.y) end,
|
|
__len = function(a) return math.sqrt(a.x*a.x + a.y*a.y) end,
|
|
__index = {
|
|
area = function(a) return a.x*a.x + a.y*a.y end,
|
|
},
|
|
}
|
|
point = ffi.metatype("point_t", mt)
|
|
|
|
local a = point(3, 4)
|
|
print(a.x, a.y) --> 3 4
|
|
print(#a) --> 5
|
|
print(a:area()) --> 25
|
|
local b = a + point(0.5, 8)
|
|
print(#b) --> 12.5
|
|
</pre>
|
|
<p>
|
|
Here's the step-by-step explanation:
|
|
</p>
|
|
<p>
|
|
<span class="mark">①</span> This defines the C type for a
|
|
two-dimensional point object.
|
|
</p>
|
|
<p>
|
|
<span class="mark">②</span> We have to declare the variable
|
|
holding the point constructor first, because it's used inside of a
|
|
metamethod.
|
|
</p>
|
|
<p>
|
|
<span class="mark">③</span> Let's define an <tt>__add</tt>
|
|
metamethod which adds the coordinates of two points and creates a new
|
|
point object. For simplicity, this function assumes that both arguments
|
|
are points. But it could be any mix of objects, if at least one operand
|
|
is of the required type (e.g. adding a point plus a number or vice
|
|
versa). Our <tt>__len</tt> metamethod returns the distance of a point to
|
|
the origin.
|
|
</p>
|
|
<p>
|
|
<span class="mark">④</span> If we run out of operators, we can
|
|
define named methods, too. Here, the <tt>__index</tt> table defines an
|
|
<tt>area</tt> function. For custom indexing needs, one might want to
|
|
define <tt>__index</tt> and <tt>__newindex</tt> <em>functions</em> instead.
|
|
</p>
|
|
<p>
|
|
<span class="mark">⑤</span> This associates the metamethods with
|
|
our C type. This only needs to be done once. For convenience, a
|
|
constructor is returned by
|
|
<a href="ext_ffi_api.html#ffi_metatype"><tt>ffi.metatype()</tt></a>.
|
|
We're not required to use it, though. The original C type can still
|
|
be used e.g. to create an array of points. The metamethods automatically
|
|
apply to any and all uses of this type.
|
|
</p>
|
|
<p>
|
|
Please note, that the association with a metatable is permanent and
|
|
<b>the metatable must not be modified afterwards!</b> Ditto for the
|
|
<tt>__index</tt> table.
|
|
</p>
|
|
<p>
|
|
<span class="mark">⑥</span> Here are some simple usage examples
|
|
for the point type and their expected results. The predefined
|
|
operations (such as <tt>a.x</tt>) can be freely mixed with the newly
|
|
defined metamethods. Note that <tt>area</tt> is a method and must be
|
|
called with the Lua syntax for methods: <tt>a:area()</tt>, not
|
|
<tt>a.area()</tt>.
|
|
</p>
|
|
<p>
|
|
The C type metamethod mechanism is most useful when used in
|
|
conjunction with C libraries that are written in an object-oriented
|
|
style. Creators return a pointer to a new instance, and methods take an
|
|
instance pointer as the first argument. Sometimes you can just point
|
|
<tt>__index</tt> to the library namespace and <tt>__gc</tt> to the
|
|
destructor and you're done. But often enough you'll want to add
|
|
convenience wrappers, e.g. to return actual Lua strings or when
|
|
returning multiple values.
|
|
</p>
|
|
<p>
|
|
Some C libraries only declare instance pointers as an opaque
|
|
<tt>void *</tt> type. In this case you can use a fake type for all
|
|
declarations, e.g. a pointer to a named (incomplete) struct will do:
|
|
<tt>typedef struct foo_type *foo_handle</tt>. The C side doesn't
|
|
know what you declare with the LuaJIT FFI, but as long as the underlying
|
|
types are compatible, everything still works.
|
|
</p>
|
|
|
|
<h2 id="idioms">Translating C Idioms</h2>
|
|
<p>
|
|
Here's a list of common C idioms and their translation to the
|
|
LuaJIT FFI:
|
|
</p>
|
|
<table class="idiomtable">
|
|
<tr class="idiomhead">
|
|
<td class="idiomdesc">Idiom</td>
|
|
<td class="idiomc">C code</td>
|
|
<td class="idiomlua">Lua code</td>
|
|
</tr>
|
|
<tr class="odd separate">
|
|
<td class="idiomdesc">Pointer dereference<br><tt>int *p;</tt></td><td class="idiomc"><tt>x = *p;<br>*p = y;</tt></td><td class="idiomlua"><tt>x = <b>p[0]</b><br><b>p[0]</b> = y</tt></td></tr>
|
|
<tr class="even">
|
|
<td class="idiomdesc">Pointer indexing<br><tt>int i, *p;</tt></td><td class="idiomc"><tt>x = p[i];<br>p[i+1] = y;</tt></td><td class="idiomlua"><tt>x = p[i]<br>p[i+1] = y</tt></td></tr>
|
|
<tr class="odd">
|
|
<td class="idiomdesc">Array indexing<br><tt>int i, a[];</tt></td><td class="idiomc"><tt>x = a[i];<br>a[i+1] = y;</tt></td><td class="idiomlua"><tt>x = a[i]<br>a[i+1] = y</tt></td></tr>
|
|
<tr class="even separate">
|
|
<td class="idiomdesc"><tt>struct</tt>/<tt>union</tt> dereference<br><tt>struct foo s;</tt></td><td class="idiomc"><tt>x = s.field;<br>s.field = y;</tt></td><td class="idiomlua"><tt>x = s.field<br>s.field = y</tt></td></tr>
|
|
<tr class="odd">
|
|
<td class="idiomdesc"><tt>struct</tt>/<tt>union</tt> pointer deref.<br><tt>struct foo *sp;</tt></td><td class="idiomc"><tt>x = sp->field;<br>sp->field = y;</tt></td><td class="idiomlua"><tt>x = <b>s.field</b><br><b>s.field</b> = y</tt></td></tr>
|
|
<tr class="even separate">
|
|
<td class="idiomdesc">Pointer arithmetic<br><tt>int i, *p;</tt></td><td class="idiomc"><tt>x = p + i;<br>y = p - i;</tt></td><td class="idiomlua"><tt>x = p + i<br>y = p - i</tt></td></tr>
|
|
<tr class="odd">
|
|
<td class="idiomdesc">Pointer difference<br><tt>int *p1, *p2;</tt></td><td class="idiomc"><tt>x = p1 - p2;</tt></td><td class="idiomlua"><tt>x = p1 - p2</tt></td></tr>
|
|
<tr class="even">
|
|
<td class="idiomdesc">Array element pointer<br><tt>int i, a[];</tt></td><td class="idiomc"><tt>x = &a[i];</tt></td><td class="idiomlua"><tt>x = <b>a+i</b></tt></td></tr>
|
|
<tr class="odd">
|
|
<td class="idiomdesc">Cast pointer to address<br><tt>int *p;</tt></td><td class="idiomc"><tt>x = (intptr_t)p;</tt></td><td class="idiomlua"><tt>x = <b>tonumber(<br> ffi.cast("intptr_t",<br> p))</b></tt></td></tr>
|
|
<tr class="even separate">
|
|
<td class="idiomdesc">Functions with outargs<br><tt>void foo(int *inoutlen);</tt></td><td class="idiomc"><tt>int len = x;<br>foo(&len);<br>y = len;</tt></td><td class="idiomlua"><tt><b>local len =<br> ffi.new("int[1]", x)<br>foo(len)<br>y = len[0]</b></tt></td></tr>
|
|
<tr class="odd">
|
|
<td class="idiomdesc"><a href="ext_ffi_semantics.html#convert_vararg">Vararg conversions</a><br><tt>int printf(char *fmt, ...);</tt></td><td class="idiomc"><tt>printf("%g", 1.0);<br>printf("%d", 1);<br> </tt></td><td class="idiomlua"><tt>printf("%g", 1);<br>printf("%d",<br> <b>ffi.new("int", 1)</b>)</tt></td></tr>
|
|
</table>
|
|
|
|
<h2 id="cache">To Cache or Not to Cache</h2>
|
|
<p>
|
|
It's a common Lua idiom to cache library functions in local variables
|
|
or upvalues, e.g.:
|
|
</p>
|
|
<pre class="code">
|
|
local byte, char = string.byte, string.char
|
|
local function foo(x)
|
|
return char(byte(x)+1)
|
|
end
|
|
</pre>
|
|
<p>
|
|
This replaces several hash-table lookups with a (faster) direct use of
|
|
a local or an upvalue. This is less important with LuaJIT, since the
|
|
JIT compiler optimizes hash-table lookups a lot and is even able to
|
|
hoist most of them out of the inner loops. It can't eliminate
|
|
<em>all</em> of them, though, and it saves some typing for often-used
|
|
functions. So there's still a place for this, even with LuaJIT.
|
|
</p>
|
|
<p>
|
|
The situation is a bit different with C function calls via the
|
|
FFI library. The JIT compiler has special logic to eliminate <em>all
|
|
of the lookup overhead</em> for functions resolved from a
|
|
<a href="ext_ffi_semantics.html#clib">C library namespace</a>!
|
|
Thus it's not helpful and actually counter-productive to cache
|
|
individual C functions like this:
|
|
</p>
|
|
<pre class="code">
|
|
local <b>funca</b>, <b>funcb</b> = ffi.C.funca, ffi.C.funcb -- <span style="color:#c00000;">Not helpful!</span>
|
|
local function foo(x, n)
|
|
for i=1,n do <b>funcb</b>(<b>funca</b>(x, i), 1) end
|
|
end
|
|
</pre>
|
|
<p>
|
|
This turns them into indirect calls and generates bigger and slower
|
|
machine code. Instead, you'll want to cache the namespace itself and
|
|
rely on the JIT compiler to eliminate the lookups:
|
|
</p>
|
|
<pre class="code">
|
|
local <b>C</b> = ffi.C -- <span style="color:#00a000;">Instead use this!</span>
|
|
local function foo(x, n)
|
|
for i=1,n do <b>C.funcb</b>(<b>C.funca</b>(x, i), 1) end
|
|
end
|
|
</pre>
|
|
<p>
|
|
This generates both shorter and faster code. So <b>don't cache
|
|
C functions</b>, but <b>do</b> cache namespaces! Most often the
|
|
namespace is already in a local variable at an outer scope, e.g. from
|
|
<tt>local lib = ffi.load(...)</tt>. Note that copying
|
|
it to a local variable in the function scope is unnecessary.
|
|
</p>
|
|
<br class="flush">
|
|
</div>
|
|
<div id="foot">
|
|
<hr class="hide">
|
|
Copyright © 2005-2023
|
|
<span class="noprint">
|
|
·
|
|
<a href="contact.html">Contact</a>
|
|
</span>
|
|
</div>
|
|
</body>
|
|
</html>
|