diff options
| author | Mike Pall <mike> | 2011-01-23 14:23:21 +0100 |
|---|---|---|
| committer | Mike Pall <mike> | 2011-01-23 14:23:21 +0100 |
| commit | 72b3fff72f6bb9cf5796bbcd50e9a490d4e02b4b (patch) | |
| tree | 5ee063bd3f5af95dddda47f30c67adfe5bc0e5ad | |
| parent | f529d22869429d458c5382cf6787f213d7bd5296 (diff) | |
| download | luajit-72b3fff72f6bb9cf5796bbcd50e9a490d4e02b4b.tar.gz luajit-72b3fff72f6bb9cf5796bbcd50e9a490d4e02b4b.tar.bz2 luajit-72b3fff72f6bb9cf5796bbcd50e9a490d4e02b4b.zip | |
FFI: Simplify initializer rules. Clarify docs.
| -rw-r--r-- | doc/ext_ffi.html | 11 | ||||
| -rw-r--r-- | doc/ext_ffi_api.html | 25 | ||||
| -rw-r--r-- | doc/ext_ffi_semantics.html | 41 | ||||
| -rw-r--r-- | src/lj_cconv.c | 9 | ||||
| -rw-r--r-- | src/lj_cconv.h | 2 | ||||
| -rw-r--r-- | src/lj_crecord.c | 3 |
6 files changed, 58 insertions, 33 deletions
diff --git a/doc/ext_ffi.html b/doc/ext_ffi.html index e8e2a62b..f496b51b 100644 --- a/doc/ext_ffi.html +++ b/doc/ext_ffi.html | |||
| @@ -73,8 +73,8 @@ The FFI library is tightly integrated into LuaJIT (it's not available | |||
| 73 | as a separate module). The code generated by the JIT-compiler for | 73 | as a separate module). The code generated by the JIT-compiler for |
| 74 | accesses to C data structures from Lua code is on par with the | 74 | accesses to C data structures from Lua code is on par with the |
| 75 | code a C compiler would generate. Calls to C functions can | 75 | code a C compiler would generate. Calls to C functions can |
| 76 | be inlined in the JIT-compiled code, unlike calls to functions bound | 76 | be inlined in JIT-compiled code, unlike calls to functions bound via |
| 77 | via the classic Lua/C API. | 77 | the classic Lua/C API. |
| 78 | </p> | 78 | </p> |
| 79 | <p> | 79 | <p> |
| 80 | This page gives a short introduction to the usage of the FFI library. | 80 | This page gives a short introduction to the usage of the FFI library. |
| @@ -253,14 +253,17 @@ would consume 40 Megabytes in plain Lua (on x64). | |||
| 253 | Next, performance: the pure Lua version runs in 9.57 seconds (52.9 | 253 | Next, performance: the pure Lua version runs in 9.57 seconds (52.9 |
| 254 | seconds with the Lua interpreter) and the FFI version runs in 0.48 | 254 | seconds with the Lua interpreter) and the FFI version runs in 0.48 |
| 255 | seconds on my machine (YMMV). That's a factor of 20x faster (110x | 255 | seconds on my machine (YMMV). That's a factor of 20x faster (110x |
| 256 | faster than with plain Lua). | 256 | faster than the Lua interpreter). |
| 257 | </p> | 257 | </p> |
| 258 | <p style="font-size: 8pt;"> | 258 | <p style="font-size: 8pt;"> |
| 259 | The avid reader may notice that converting the pure Lua version over | 259 | The avid reader may notice that converting the pure Lua version over |
| 260 | to use array indexes for the colors (<tt>[1]</tt> instead of | 260 | to use array indexes for the colors (<tt>[1]</tt> instead of |
| 261 | <tt>.red</tt>, <tt>[2]</tt> instead of <tt>.green</tt> etc.) ought to | 261 | <tt>.red</tt>, <tt>[2]</tt> instead of <tt>.green</tt> etc.) ought to |
| 262 | be more compact and faster. This is certainly true (by a factor of | 262 | be more compact and faster. This is certainly true (by a factor of |
| 263 | ~1.7x), but the resulting code would be less idiomatic and rather | 263 | ~1.7x). Switching to a struct-of-arrays would help, too. |
| 264 | </p> | ||
| 265 | <p style="font-size: 8pt;"> | ||
| 266 | However the resulting code would be less idiomatic and rather | ||
| 264 | error-prone. And it still doesn't get even close to the performance of | 267 | error-prone. And it still doesn't get even close to the performance of |
| 265 | the FFI version of the code. Also, high-level data structures cannot | 268 | the FFI version of the code. Also, high-level data structures cannot |
| 266 | be easily passed to other C functions, especially I/O functions, | 269 | be easily passed to other C functions, especially I/O functions, |
diff --git a/doc/ext_ffi_api.html b/doc/ext_ffi_api.html index f985d965..f0c4de90 100644 --- a/doc/ext_ffi_api.html +++ b/doc/ext_ffi_api.html | |||
| @@ -195,23 +195,10 @@ require the <tt>nelem</tt> argument. The second syntax uses a ctype as | |||
| 195 | a constructor and is otherwise fully equivalent. | 195 | a constructor and is otherwise fully equivalent. |
| 196 | </p> | 196 | </p> |
| 197 | <p> | 197 | <p> |
| 198 | The <tt>init</tt> arguments provide optional initializers. The created | 198 | The cdata object is initialized according to the |
| 199 | cdata object is filled with zero bytes if no initializers are given. | 199 | <a href="ext_ffi_semantics.html#init">rules for initializers</a>, |
| 200 | Scalar types accept a single initializer. Aggregates can either be | 200 | using the optional <tt>init</tt> arguments. Excess initializers cause |
| 201 | initialized with a flat list of initializers or a single aggregate | 201 | an error. |
| 202 | initializer (see the <a href="ext_ffi_semantics.html#convert">C type | ||
| 203 | conversion rules</a>). Excess initializers cause an error. | ||
| 204 | </p> | ||
| 205 | <p> | ||
| 206 | If a single initializer is given for an array, it's repeated for all | ||
| 207 | remaining elements. This doesn't happen if two or more initializers | ||
| 208 | are given — all uninitialized elements are filled with zero | ||
| 209 | bytes. The fields of a <tt>struct</tt> are initialized in the order of | ||
| 210 | their declaration. Uninitialized fields are filled with zero bytes. | ||
| 211 | Only the first field of <tt>union</tt> can be initialized with a flat | ||
| 212 | initializer. Elements or fields which are aggregates themselves are | ||
| 213 | initialized with a <em>single</em> <tt>init</tt> argument, but this | ||
| 214 | may be an aggregate initializer of course. | ||
| 215 | </p> | 202 | </p> |
| 216 | <p> | 203 | <p> |
| 217 | Performance notice: if you want to create many objects of one kind, | 204 | Performance notice: if you want to create many objects of one kind, |
| @@ -357,8 +344,8 @@ order of arguments! | |||
| 357 | <h3 id="ffi_abi"><tt>status = ffi.abi(param)</tt></h3> | 344 | <h3 id="ffi_abi"><tt>status = ffi.abi(param)</tt></h3> |
| 358 | <p> | 345 | <p> |
| 359 | Returns <tt>true</tt> if <tt>param</tt> (a Lua string) applies for the | 346 | Returns <tt>true</tt> if <tt>param</tt> (a Lua string) applies for the |
| 360 | target ABI (Application Binary Interface). Otherwise returns | 347 | target ABI (Application Binary Interface). Returns <tt>false</tt> |
| 361 | <tt>false</tt>. The following parameters are currently defined: | 348 | otherwise. The following parameters are currently defined: |
| 362 | </p> | 349 | </p> |
| 363 | <table class="abitable"> | 350 | <table class="abitable"> |
| 364 | <tr class="abihead"> | 351 | <tr class="abihead"> |
diff --git a/doc/ext_ffi_semantics.html b/doc/ext_ffi_semantics.html index 598d44c9..4a1b6c11 100644 --- a/doc/ext_ffi_semantics.html +++ b/doc/ext_ffi_semantics.html | |||
| @@ -70,6 +70,47 @@ TODO | |||
| 70 | TODO | 70 | TODO |
| 71 | </p> | 71 | </p> |
| 72 | 72 | ||
| 73 | <h2 id="init">Initializers</h2> | ||
| 74 | <p> | ||
| 75 | Creating a cdata object with <a href="ffi_ext_api.html#ffi_new">ffi.new()</a> | ||
| 76 | or the equivalent constructor syntax always initializes its contents, | ||
| 77 | too. Different rules apply, depending on the number of optional | ||
| 78 | initializers and the C types involved: | ||
| 79 | </p> | ||
| 80 | <ul> | ||
| 81 | <li>If no initializers are given, the object is filled with zero bytes.</li> | ||
| 82 | |||
| 83 | <li>Scalar types (numbers and pointers) accept a single initializer. | ||
| 84 | The standard <a href="#convert">C type conversion rules</a> | ||
| 85 | apply.</li> | ||
| 86 | |||
| 87 | <li>Valarrays (complex numbers and vectors) are treated like scalars | ||
| 88 | when a single initializer is given. Otherwise they are treated like | ||
| 89 | regular arrays.</li> | ||
| 90 | |||
| 91 | <li>Aggregate types (arrays and structs) accept either a single | ||
| 92 | compound initializer (Lua table or string) or a flat list of | ||
| 93 | initializers.</li> | ||
| 94 | |||
| 95 | <li>The elements of an array are initialized, starting at index zero. | ||
| 96 | If a single initializer is given for an array, it's repeated for all | ||
| 97 | remaining elements. This doesn't happen if two or more initializers | ||
| 98 | are given: all remaining uninitialized elements are filled with zero | ||
| 99 | bytes.</li> | ||
| 100 | |||
| 101 | <li>The fields of a <tt>struct</tt> are initialized in the order of | ||
| 102 | their declaration. Uninitialized fields are filled with zero | ||
| 103 | bytes.</li> | ||
| 104 | |||
| 105 | <li>Only the first field of a <tt>union</tt> can be initialized with a | ||
| 106 | flat initializer.</li> | ||
| 107 | |||
| 108 | <li>Elements or fields which are aggregates themselves are initialized | ||
| 109 | with a <em>single</em> initializer, but this may be a compound | ||
| 110 | initializer or a compatible aggregate, of course.</li> | ||
| 111 | |||
| 112 | </ul> | ||
| 113 | |||
| 73 | <h2 id="clib">C Library Namespaces</h2> | 114 | <h2 id="clib">C Library Namespaces</h2> |
| 74 | <p> | 115 | <p> |
| 75 | A C library namespace is a special kind of object which allows | 116 | A C library namespace is a special kind of object which allows |
diff --git a/src/lj_cconv.c b/src/lj_cconv.c index ac6374ed..d4578f88 100644 --- a/src/lj_cconv.c +++ b/src/lj_cconv.c | |||
| @@ -679,17 +679,12 @@ static void cconv_struct_init(CTState *cts, CType *d, CTSize sz, uint8_t *dp, | |||
| 679 | ** This is true if an aggregate is to be initialized with a value. | 679 | ** This is true if an aggregate is to be initialized with a value. |
| 680 | ** Valarrays are treated as values here so ct_tv handles (V|C, I|F). | 680 | ** Valarrays are treated as values here so ct_tv handles (V|C, I|F). |
| 681 | */ | 681 | */ |
| 682 | int lj_cconv_multi_init(CTState *cts, CType *d, TValue *o) | 682 | int lj_cconv_multi_init(CType *d, TValue *o) |
| 683 | { | 683 | { |
| 684 | if (!(ctype_isrefarray(d->info) || ctype_isstruct(d->info))) | 684 | if (!(ctype_isrefarray(d->info) || ctype_isstruct(d->info))) |
| 685 | return 0; /* Destination is not an aggregate. */ | 685 | return 0; /* Destination is not an aggregate. */ |
| 686 | if (tvistab(o) || (tvisstr(o) && !ctype_isstruct(d->info))) | 686 | if (tvistab(o) || (tvisstr(o) && !ctype_isstruct(d->info))) |
| 687 | return 0; /* Initializer is not a value. */ | 687 | return 0; /* Initializer is not a value. */ |
| 688 | if (tviscdata(o)) { | ||
| 689 | CTInfo info = lj_ctype_rawref(cts, cdataV(o)->typeid)->info; | ||
| 690 | if (ctype_isrefarray(info) || ctype_isstruct(info)) | ||
| 691 | return 0; /* Initializer is not a value. */ | ||
| 692 | } | ||
| 693 | return 1; /* Otherwise the initializer is a value. */ | 688 | return 1; /* Otherwise the initializer is a value. */ |
| 694 | } | 689 | } |
| 695 | 690 | ||
| @@ -699,7 +694,7 @@ void lj_cconv_ct_init(CTState *cts, CType *d, CTSize sz, | |||
| 699 | { | 694 | { |
| 700 | if (len == 0) | 695 | if (len == 0) |
| 701 | memset(dp, 0, sz); | 696 | memset(dp, 0, sz); |
| 702 | else if (len == 1 && !lj_cconv_multi_init(cts, d, o)) | 697 | else if (len == 1 && !lj_cconv_multi_init(d, o)) |
| 703 | lj_cconv_ct_tv(cts, d, dp, o, 0); | 698 | lj_cconv_ct_tv(cts, d, dp, o, 0); |
| 704 | else if (ctype_isarray(d->info)) /* Also handles valarray init with len>1. */ | 699 | else if (ctype_isarray(d->info)) /* Also handles valarray init with len>1. */ |
| 705 | cconv_array_init(cts, d, sz, dp, o, len); | 700 | cconv_array_init(cts, d, sz, dp, o, len); |
diff --git a/src/lj_cconv.h b/src/lj_cconv.h index acc09af9..494f9d4e 100644 --- a/src/lj_cconv.h +++ b/src/lj_cconv.h | |||
| @@ -58,7 +58,7 @@ LJ_FUNC int lj_cconv_tv_bf(CTState *cts, CType *s, TValue *o, uint8_t *sp); | |||
| 58 | LJ_FUNC void lj_cconv_ct_tv(CTState *cts, CType *d, | 58 | LJ_FUNC void lj_cconv_ct_tv(CTState *cts, CType *d, |
| 59 | uint8_t *dp, TValue *o, CTInfo flags); | 59 | uint8_t *dp, TValue *o, CTInfo flags); |
| 60 | LJ_FUNC void lj_cconv_bf_tv(CTState *cts, CType *d, uint8_t *dp, TValue *o); | 60 | LJ_FUNC void lj_cconv_bf_tv(CTState *cts, CType *d, uint8_t *dp, TValue *o); |
| 61 | LJ_FUNC int lj_cconv_multi_init(CTState *cts, CType *d, TValue *o); | 61 | LJ_FUNC int lj_cconv_multi_init(CType *d, TValue *o); |
| 62 | LJ_FUNC void lj_cconv_ct_init(CTState *cts, CType *d, CTSize sz, | 62 | LJ_FUNC void lj_cconv_ct_init(CTState *cts, CType *d, CTSize sz, |
| 63 | uint8_t *dp, TValue *o, MSize len); | 63 | uint8_t *dp, TValue *o, MSize len); |
| 64 | 64 | ||
diff --git a/src/lj_crecord.c b/src/lj_crecord.c index c6577975..681c5029 100644 --- a/src/lj_crecord.c +++ b/src/lj_crecord.c | |||
| @@ -566,8 +566,7 @@ static void crec_alloc(jit_State *J, RecordFFData *rd, CTypeID id) | |||
| 566 | CType *d = ctype_raw(cts, id); | 566 | CType *d = ctype_raw(cts, id); |
| 567 | TRef trcd = emitir(IRTG(IR_CNEW, IRT_CDATA), trid, TREF_NIL); | 567 | TRef trcd = emitir(IRTG(IR_CNEW, IRT_CDATA), trid, TREF_NIL); |
| 568 | J->base[0] = trcd; | 568 | J->base[0] = trcd; |
| 569 | if (J->base[1] && !J->base[2] && | 569 | if (J->base[1] && !J->base[2] && !lj_cconv_multi_init(d, &rd->argv[1])) { |
| 570 | !lj_cconv_multi_init(cts, d, &rd->argv[1])) { | ||
| 571 | goto single_init; | 570 | goto single_init; |
| 572 | } else if (ctype_isarray(d->info)) { | 571 | } else if (ctype_isarray(d->info)) { |
| 573 | CType *dc = ctype_rawchild(cts, d); /* Array element type. */ | 572 | CType *dc = ctype_rawchild(cts, d); /* Array element type. */ |
