diff options
author | Mike Pall <mike> | 2011-02-11 01:21:46 +0100 |
---|---|---|
committer | Mike Pall <mike> | 2011-02-11 01:21:46 +0100 |
commit | a5aade2fa9ff89f9f3c4a91261071299de0d0fa4 (patch) | |
tree | d253cfe022944c9754ebe43810a73c141130f058 /doc/ext_ffi_tutorial.html | |
parent | a2f9f1f831c77b19433b9f8858b9c1db0e421800 (diff) | |
download | luajit-a5aade2fa9ff89f9f3c4a91261071299de0d0fa4.tar.gz luajit-a5aade2fa9ff89f9f3c4a91261071299de0d0fa4.tar.bz2 luajit-a5aade2fa9ff89f9f3c4a91261071299de0d0fa4.zip |
FFI: Finish FFI docs.
Diffstat (limited to 'doc/ext_ffi_tutorial.html')
-rw-r--r-- | doc/ext_ffi_tutorial.html | 352 |
1 files changed, 348 insertions, 4 deletions
diff --git a/doc/ext_ffi_tutorial.html b/doc/ext_ffi_tutorial.html index 11e83339..c43b223b 100644 --- a/doc/ext_ffi_tutorial.html +++ b/doc/ext_ffi_tutorial.html | |||
@@ -8,6 +8,13 @@ | |||
8 | <meta name="Language" content="en"> | 8 | <meta name="Language" content="en"> |
9 | <link rel="stylesheet" type="text/css" href="bluequad.css" media="screen"> | 9 | <link rel="stylesheet" type="text/css" href="bluequad.css" media="screen"> |
10 | <link rel="stylesheet" type="text/css" href="bluequad-print.css" media="print"> | 10 | <link rel="stylesheet" type="text/css" href="bluequad-print.css" media="print"> |
11 | <style type="text/css"> | ||
12 | table.idiomtable { line-height: 1.2; } | ||
13 | tr.idiomhead td { font-weight: bold; } | ||
14 | td.idiomc { width: 12em; } | ||
15 | td.idiomlua { width: 14em; } | ||
16 | td.idiomlua b { font-weight: normal; color: #2142bf; } | ||
17 | </style> | ||
11 | </head> | 18 | </head> |
12 | <body> | 19 | <body> |
13 | <div id="site"> | 20 | <div id="site"> |
@@ -33,8 +40,6 @@ | |||
33 | </li><li> | 40 | </li><li> |
34 | <a href="ext_ffi_api.html">ffi.* API</a> | 41 | <a href="ext_ffi_api.html">ffi.* API</a> |
35 | </li><li> | 42 | </li><li> |
36 | <a href="ext_ffi_int64.html">64 bit Integers</a> | ||
37 | </li><li> | ||
38 | <a href="ext_ffi_semantics.html">FFI Semantics</a> | 43 | <a href="ext_ffi_semantics.html">FFI Semantics</a> |
39 | </li></ul> | 44 | </li></ul> |
40 | </li><li> | 45 | </li><li> |
@@ -57,7 +62,14 @@ | |||
57 | </div> | 62 | </div> |
58 | <div id="main"> | 63 | <div id="main"> |
59 | <p> | 64 | <p> |
60 | TODO | 65 | This page is intended to give you an overview of the features of the FFI |
66 | library by presenting a few use cases and guidelines. | ||
67 | </p> | ||
68 | <p> | ||
69 | This page makes no attempt to explain all of the FFI library, though. | ||
70 | You'll want to have a look at the <a href="ext_ffi_api.html">ffi.* API | ||
71 | function reference</a> and the <a href="ext_ffi_semantics.html">FFI | ||
72 | semantics</a> to learn more. | ||
61 | </p> | 73 | </p> |
62 | 74 | ||
63 | <h2 id="load">Loading the FFI Library</h2> | 75 | <h2 id="load">Loading the FFI Library</h2> |
@@ -76,7 +88,339 @@ of globals — you really need to use the local variable. The | |||
76 | <tt>require</tt> function ensures the library is only loaded once. | 88 | <tt>require</tt> function ensures the library is only loaded once. |
77 | </p> | 89 | </p> |
78 | 90 | ||
79 | <h2>TODO</h2> | 91 | <h2 id="sleep">Accessing Standard System Functions</h2> |
92 | <p> | ||
93 | The following code explains how to access standard system functions. | ||
94 | We slowly print two lines of dots by sleeping for 10 milliseconds | ||
95 | after each dot: | ||
96 | </p> | ||
97 | <pre class="code"> | ||
98 | local ffi = require("ffi") | ||
99 | ffi.cdef[[ <span style="color:#f0f4ff;">//</span><span style="color:#4040c0;">①</span> | ||
100 | <span style="color:#00a000;">void Sleep(int ms); | ||
101 | int poll(struct pollfd *fds, unsigned long nfds, int timeout);</span> | ||
102 | ]] | ||
103 | |||
104 | local sleep | ||
105 | if ffi.os == "Windows" then <span style="color:#f0f4ff;">--</span><span style="color:#4040c0;">②</span> | ||
106 | function sleep(s) <span style="color:#f0f4ff;">--</span><span style="color:#4040c0;">③</span> | ||
107 | ffi.C.Sleep(s*1000) <span style="color:#f0f4ff;">--</span><span style="color:#4040c0;">④</span> | ||
108 | end | ||
109 | else | ||
110 | function sleep(s) | ||
111 | ffi.C.poll(nil, 0, s*1000) <span style="color:#f0f4ff;">--</span><span style="color:#4040c0;">⑤</span> | ||
112 | end | ||
113 | end | ||
114 | |||
115 | for i=1,160 do | ||
116 | io.write("."); io.flush() | ||
117 | sleep(0.01) <span style="color:#f0f4ff;">--</span><span style="color:#4040c0;">⑥</span> | ||
118 | end | ||
119 | io.write("\n") | ||
120 | </pre> | ||
121 | <p> | ||
122 | Here's the step-by-step explanation: | ||
123 | </p> | ||
124 | <p> | ||
125 | <span style="color:#4040c0;">①</span> This defines the | ||
126 | C library functions we're going to use. The part inside the | ||
127 | double-brackets (in green) is just standard C syntax. You can | ||
128 | usually get this info from the C header files or the | ||
129 | documentation provided by each C library or C compiler. | ||
130 | </p> | ||
131 | <p> | ||
132 | <span style="color:#4040c0;">②</span> The difficulty we're | ||
133 | facing here, is that there are different standards to choose from. | ||
134 | Windows has a simple <tt>Sleep()</tt> function. On other systems there | ||
135 | are a variety of functions available to achieve sub-second sleeps, but | ||
136 | with no clear consensus. Thankfully <tt>poll()</tt> can be used for | ||
137 | this task, too, and it's present on most non-Windows systems. The | ||
138 | check for <tt>ffi.os</tt> makes sure we use the Windows-specific | ||
139 | function only on Windows systems. | ||
140 | </p> | ||
141 | <p> | ||
142 | <span style="color:#4040c0;">③</span> Here we're wrapping the | ||
143 | call to the C function in a Lua function. This isn't strictly | ||
144 | necessary, but it's helpful to deal with system-specific issues only | ||
145 | in one part of the code. The way we're wrapping it ensures the check | ||
146 | for the OS is only done during initialization and not for every call. | ||
147 | </p> | ||
148 | <p> | ||
149 | <span style="color:#4040c0;">④</span> A more subtle point is | ||
150 | that we defined our <tt>sleep()</tt> function (for the sake of this | ||
151 | example) as taking the number of seconds, but accepting fractional | ||
152 | seconds. Multiplying this by 1000 gets us milliseconds, but that still | ||
153 | leaves it a Lua number, which is a floating-point value. Alas, the | ||
154 | <tt>Sleep()</tt> function only accepts an integer value. Luckily for | ||
155 | us, the FFI library automatically performs the conversion when calling | ||
156 | the function (truncating the FP value towards zero, like in C). | ||
157 | </p> | ||
158 | <p style="font-size: 8pt;"> | ||
159 | Some readers will notice that <tt>Sleep()</tt> is part of | ||
160 | <tt>KERNEL32.DLL</tt> and is also a <tt>stdcall</tt> function. So how | ||
161 | can this possibly work? The FFI library provides the <tt>ffi.C</tt> | ||
162 | default C library namespace, which allows calling functions from | ||
163 | the default set of libraries, like a C compiler would. Also, the | ||
164 | FFI library automatically detects <tt>stdcall</tt> functions, so you | ||
165 | don't need to declare them as such. | ||
166 | </p> | ||
167 | <p> | ||
168 | <span style="color:#4040c0;">⑤</span> The <tt>poll()</tt> | ||
169 | function takes a couple more arguments we're not going to use. You can | ||
170 | simply use <tt>nil</tt> to pass a <tt>NULL</tt> pointer and <tt>0</tt> | ||
171 | for the <tt>nfds</tt> parameter. Please note that the | ||
172 | number <tt>0</tt> <em>does not convert to a pointer value</em>, | ||
173 | unlike in C++. You really have to pass pointers to pointer arguments | ||
174 | and numbers to number arguments. | ||
175 | </p> | ||
176 | <p style="font-size: 8pt;"> | ||
177 | The page on <a href="ext_ffi_semantics.html">FFI semantics</a> has all | ||
178 | of the gory details about | ||
179 | <a href="ext_ffi_semantics.html#convert">conversions between Lua | ||
180 | objects and C types</a>. For the most part you don't have to deal | ||
181 | with this, as it's performed automatically and it's carefully designed | ||
182 | to bridge the semantic differences between Lua and C. | ||
183 | </p> | ||
184 | <p> | ||
185 | <span style="color:#4040c0;">⑥</span> Now that we have defined | ||
186 | our own <tt>sleep()</tt> function, we can just call it from plain Lua | ||
187 | code. That wasn't so bad, huh? Turning these boring animated dots into | ||
188 | a fascinating best-selling game is left as an exercise for the reader. | ||
189 | :-) | ||
190 | </p> | ||
191 | |||
192 | <h2 id="zlib">Accessing the zlib Compression Library</h2> | ||
193 | <p> | ||
194 | The following code shows how to access the <a | ||
195 | href="http://zlib.net/">zlib</a> compression library from Lua code. | ||
196 | We'll define two convenience wrapper functions that take a string and | ||
197 | compress or uncompress it to another string: | ||
198 | </p> | ||
199 | <pre class="code"> | ||
200 | local ffi = require("ffi") | ||
201 | ffi.cdef[[ <span style="color:#f0f4ff;">//</span><span style="color:#4040c0;">①</span> | ||
202 | <span style="color:#00a000;">unsigned long compressBound(unsigned long sourceLen); | ||
203 | int compress2(uint8_t *dest, unsigned long *destLen, | ||
204 | const uint8_t *source, unsigned long sourceLen, int level); | ||
205 | int uncompress(uint8_t *dest, unsigned long *destLen, | ||
206 | const uint8_t *source, unsigned long sourceLen);</span> | ||
207 | ]] | ||
208 | local zlib = ffi.load(ffi.os == "Windows" and "zlib1" or "z") <span style="color:#f0f4ff;">--</span><span style="color:#4040c0;">②</span> | ||
209 | |||
210 | local function compress(txt) | ||
211 | local n = zlib.compressBound(#txt) <span style="color:#f0f4ff;">--</span><span style="color:#4040c0;">③</span> | ||
212 | local buf = ffi.new("uint8_t[?]", n) | ||
213 | local buflen = ffi.new("unsigned long[1]", n) <span style="color:#f0f4ff;">--</span><span style="color:#4040c0;">④</span> | ||
214 | local res = zlib.compress2(buf, buflen, txt, #txt, 9) | ||
215 | assert(res == 0) | ||
216 | return ffi.string(buf, buflen[0]) <span style="color:#f0f4ff;">--</span><span style="color:#4040c0;">⑤</span> | ||
217 | end | ||
218 | |||
219 | local function uncompress(comp, n) <span style="color:#f0f4ff;">--</span><span style="color:#4040c0;">⑥</span> | ||
220 | local buf = ffi.new("uint8_t[?]", n) | ||
221 | local buflen = ffi.new("unsigned long[1]", n) | ||
222 | local res = zlib.uncompress(buf, buflen, comp, #comp) | ||
223 | assert(res == 0) | ||
224 | return ffi.string(buf, buflen[0]) | ||
225 | end | ||
226 | |||
227 | -- Simple test code. <span style="color:#f0f4ff;">--</span><span style="color:#4040c0;">⑦</span> | ||
228 | local txt = string.rep("abcd", 1000) | ||
229 | print("Uncompressed size: ", #txt) | ||
230 | local c = compress(txt) | ||
231 | print("Compressed size: ", #c) | ||
232 | local txt2 = uncompress(c, #txt) | ||
233 | assert(txt2 == txt) | ||
234 | </pre> | ||
235 | <p> | ||
236 | Here's the step-by-step explanation: | ||
237 | </p> | ||
238 | <p> | ||
239 | <span style="color:#4040c0;">①</span> This defines some of the | ||
240 | C functions provided by zlib. For the sake of this example, some | ||
241 | type indirections have been reduced and it uses the pre-defined | ||
242 | fixed-size integer types, while still adhering to the zlib API/ABI. | ||
243 | </p> | ||
244 | <p> | ||
245 | <span style="color:#4040c0;">②</span> This loads the zlib shared | ||
246 | library. On POSIX systems it's named <tt>libz.so</tt> and usually | ||
247 | comes pre-installed. Since <tt>ffi.load()</tt> automatically adds any | ||
248 | missing standard prefixes/suffixes, we can simply load the | ||
249 | <tt>"z"</tt> library. On Windows it's named <tt>zlib1.dll</tt> and | ||
250 | you'll have to download it first from the | ||
251 | <a href="http://zlib.net/"><span class="ext">»</span> zlib site</a>. The check for | ||
252 | <tt>ffi.os</tt> makes sure we pass the right name to | ||
253 | <tt>ffi.load()</tt>. | ||
254 | </p> | ||
255 | <p> | ||
256 | <span style="color:#4040c0;">③</span> First, the maximum size of | ||
257 | the compression buffer is obtained by calling the | ||
258 | <tt>zlib.compressBound</tt> function with the length of the | ||
259 | uncompressed string. The next line allocates a byte buffer of this | ||
260 | size. The <tt>[?]</tt> in the type specification indicates a | ||
261 | variable-length array (VLA). The actual number of elements of this | ||
262 | array is given as the 2nd argument to <tt>ffi.new()</tt>. | ||
263 | </p> | ||
264 | <p> | ||
265 | <span style="color:#4040c0;">④</span> This may look strange at | ||
266 | first, but have a look at the declaration of the <tt>compress2</tt> | ||
267 | function from zlib: the destination length is defined as a pointer! | ||
268 | This is because you pass in the maximum buffer size and get back the | ||
269 | actual length that was used. | ||
270 | </p> | ||
271 | <p> | ||
272 | In C you'd pass in the address of a local variable | ||
273 | (<tt>&buflen</tt>). But since there's no address-of operator in | ||
274 | Lua, we'll just pass in a one-element array. Conveniently it can be | ||
275 | initialized with the maximum buffer size in one step. Calling the | ||
276 | actual <tt>zlib.compress2</tt> function is then straightforward. | ||
277 | </p> | ||
278 | <p> | ||
279 | <span style="color:#4040c0;">⑤</span> We want to return the | ||
280 | compressed data as a Lua string, so we'll use <tt>ffi.string()</tt>. | ||
281 | It needs a pointer to the start of the data and the actual length. The | ||
282 | length has been returned in the <tt>buflen</tt> array, so we'll just | ||
283 | get it from there. | ||
284 | </p> | ||
285 | <p style="font-size: 8pt;"> | ||
286 | Note that since the function returns now, the <tt>buf</tt> and | ||
287 | <tt>buflen</tt> variables will eventually be garbage collected. This | ||
288 | is fine, because <tt>ffi.string()</tt> has copied the contents to a | ||
289 | newly created (interned) Lua string. If you plan to call this function | ||
290 | lots of times, consider reusing the buffers and/or handing back the | ||
291 | results in buffers instead of strings. This will reduce the overhead | ||
292 | for garbage collection and string interning. | ||
293 | </p> | ||
294 | <p> | ||
295 | <span style="color:#4040c0;">⑥</span> The <tt>uncompress</tt> | ||
296 | functions does the exact opposite of the <tt>compress</tt> function. | ||
297 | The compressed data doesn't include the size of the original string, | ||
298 | so this needs to be passed in. Otherwise no surprises here. | ||
299 | </p> | ||
300 | <p> | ||
301 | <span style="color:#4040c0;">⑦</span> The code, that makes use | ||
302 | of the functions we just defined, is just plain Lua code. It doesn't | ||
303 | need to know anything about the LuaJIT FFI — the convenience | ||
304 | wrapper functions completely hide it. | ||
305 | </p> | ||
306 | <p> | ||
307 | One major advantage of the LuaJIT FFI is that you are now able to | ||
308 | write those wrappers <em>in Lua</em>. And at a fraction of the time it | ||
309 | would cost you to create an extra C module using the Lua/C API. | ||
310 | Many of the simpler C functions can probably be used directly | ||
311 | from your Lua code, without any wrappers. | ||
312 | </p> | ||
313 | <p style="font-size: 8pt;"> | ||
314 | Side note: the zlib API uses the <tt>long</tt> type for passing | ||
315 | lengths and sizes around. But all those zlib functions actually only | ||
316 | deal with 32 bit values. This is an unfortunate choice for a | ||
317 | public API, but may be explained by zlib's history — we'll just | ||
318 | have to deal with it. | ||
319 | </p> | ||
320 | <p style="font-size: 8pt;"> | ||
321 | First, you should know that a <tt>long</tt> is a 64 bit type e.g. | ||
322 | on POSIX/x64 systems, but a 32 bit type on Windows/x64 and on | ||
323 | 32 bit systems. Thus a <tt>long</tt> result can be either a plain | ||
324 | Lua number or a boxed 64 bit integer cdata object, depending on | ||
325 | the target system. | ||
326 | </p> | ||
327 | <p style="font-size: 8pt;"> | ||
328 | Ok, so the <tt>ffi.*</tt> functions generally accept cdata objects | ||
329 | wherever you'd want to use a number. That's why we get a away with | ||
330 | passing <tt>n</tt> to <tt>ffi.string()</tt> above. But other Lua | ||
331 | library functions or modules don't know how to deal with this. So for | ||
332 | maximum portability one needs to use <tt>tonumber()</tt> on returned | ||
333 | <tt>long</tt> results before passing them on. Otherwise the | ||
334 | application might work on some systems, but would fail in a POSIX/x64 | ||
335 | environment. | ||
336 | </p> | ||
337 | |||
338 | <h2 id="idioms">Translating C Idioms</h2> | ||
339 | <p> | ||
340 | Here's a list of common C idioms and their translation to the | ||
341 | LuaJIT FFI: | ||
342 | </p> | ||
343 | <table class="idiomtable"> | ||
344 | <tr class="idiomhead"> | ||
345 | <td class="idiomdesc">Idiom</td> | ||
346 | <td class="idiomc">C code</td> | ||
347 | <td class="idiomlua">Lua code</td> | ||
348 | </tr> | ||
349 | <tr class="odd separate"> | ||
350 | <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> | ||
351 | <tr class="even"> | ||
352 | <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> | ||
353 | <tr class="odd"> | ||
354 | <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> | ||
355 | <tr class="even separate"> | ||
356 | <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> | ||
357 | <tr class="odd"> | ||
358 | <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> | ||
359 | <tr class="even separate"> | ||
360 | <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> | ||
361 | <tr class="odd"> | ||
362 | <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> | ||
363 | <tr class="even"> | ||
364 | <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> | ||
365 | <tr class="odd"> | ||
366 | <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> | ||
367 | <tr class="even separate"> | ||
368 | <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> | ||
369 | <tr class="odd"> | ||
370 | <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> | ||
371 | </table> | ||
372 | |||
373 | <h2 id="cache">To Cache or Not to Cache</h2> | ||
374 | <p> | ||
375 | It's a common Lua idiom to cache library functions in local variables | ||
376 | or upvalues, e.g.: | ||
377 | </p> | ||
378 | <pre class="code"> | ||
379 | local byte, char = string.byte, string.char | ||
380 | local function foo(x) | ||
381 | return char(byte(x)+1) | ||
382 | end | ||
383 | </pre> | ||
384 | <p> | ||
385 | This replaces several hash-table lookups with a (faster) direct use of | ||
386 | a local or an upvalue. This is less important with LuaJIT, since the | ||
387 | JIT compiler optimizes hash-table lookups a lot and is even able to | ||
388 | hoist most of them out of the inner loops. It can't eliminate | ||
389 | <em>all</em> of them, though, and it saves some typing for often-used | ||
390 | functions. So there's still a place for this, even with LuaJIT. | ||
391 | </p> | ||
392 | <p> | ||
393 | The situation is a bit different with C function calls via the | ||
394 | FFI library. The JIT compiler has special logic to eliminate <em>all | ||
395 | of the lookup overhead</em> for functions resolved from a | ||
396 | <a href="ext_ffi_semantics.html#clib">C library namespace</a>! | ||
397 | Thus it's not helpful and actually counter-productive to cache | ||
398 | individual C functions like this: | ||
399 | </p> | ||
400 | <pre class="code"> | ||
401 | local <b>funca</b>, <b>funcb</b> = ffi.C.funcb, ffi.C.funcb -- <span style="color:#c00000;">Not helpful!</span> | ||
402 | local function foo(x, n) | ||
403 | for i=1,n do <b>funcb</b>(<b>funca</b>(x, i), 1) end | ||
404 | end | ||
405 | </pre> | ||
406 | <p> | ||
407 | This turns them into indirect calls and generates bigger and slower | ||
408 | machine code. Instead you'll want to cache the namespace itself and | ||
409 | rely on the JIT compiler to eliminate the lookups: | ||
410 | </p> | ||
411 | <pre class="code"> | ||
412 | local <b>C</b> = ffi.C -- <span style="color:#00a000;">Instead use this!</span> | ||
413 | local function foo(x, n) | ||
414 | for i=1,n do <b>C.funcb</b>(<b>C.funca</b>(x, i), 1) end | ||
415 | end | ||
416 | </pre> | ||
417 | <p> | ||
418 | This generates both shorter and faster code. So <b>don't cache | ||
419 | C functions</b>, but <b>do</b> cache namespaces! Most often the | ||
420 | namespace is already in a local variable at an outer scope, e.g. from | ||
421 | <tt>local lib = ffi.load(...)</tt>. Note that copying | ||
422 | it to a local variable in the function scope is unnecessary. | ||
423 | </p> | ||
80 | <br class="flush"> | 424 | <br class="flush"> |
81 | </div> | 425 | </div> |
82 | <div id="foot"> | 426 | <div id="foot"> |