FFI: Simplify initializer rules. Clarify docs.
This commit is contained in:
parent
f529d22869
commit
72b3fff72f
@ -73,8 +73,8 @@ The FFI library is tightly integrated into LuaJIT (it's not available
|
|||||||
as a separate module). The code generated by the JIT-compiler for
|
as a separate module). The code generated by the JIT-compiler for
|
||||||
accesses to C data structures from Lua code is on par with the
|
accesses to C data structures from Lua code is on par with the
|
||||||
code a C compiler would generate. Calls to C functions can
|
code a C compiler would generate. Calls to C functions can
|
||||||
be inlined in the JIT-compiled code, unlike calls to functions bound
|
be inlined in JIT-compiled code, unlike calls to functions bound via
|
||||||
via the classic Lua/C API.
|
the classic Lua/C API.
|
||||||
</p>
|
</p>
|
||||||
<p>
|
<p>
|
||||||
This page gives a short introduction to the usage of the FFI library.
|
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).
|
|||||||
Next, performance: the pure Lua version runs in 9.57 seconds (52.9
|
Next, performance: the pure Lua version runs in 9.57 seconds (52.9
|
||||||
seconds with the Lua interpreter) and the FFI version runs in 0.48
|
seconds with the Lua interpreter) and the FFI version runs in 0.48
|
||||||
seconds on my machine (YMMV). That's a factor of 20x faster (110x
|
seconds on my machine (YMMV). That's a factor of 20x faster (110x
|
||||||
faster than with plain Lua).
|
faster than the Lua interpreter).
|
||||||
</p>
|
</p>
|
||||||
<p style="font-size: 8pt;">
|
<p style="font-size: 8pt;">
|
||||||
The avid reader may notice that converting the pure Lua version over
|
The avid reader may notice that converting the pure Lua version over
|
||||||
to use array indexes for the colors (<tt>[1]</tt> instead of
|
to use array indexes for the colors (<tt>[1]</tt> instead of
|
||||||
<tt>.red</tt>, <tt>[2]</tt> instead of <tt>.green</tt> etc.) ought to
|
<tt>.red</tt>, <tt>[2]</tt> instead of <tt>.green</tt> etc.) ought to
|
||||||
be more compact and faster. This is certainly true (by a factor of
|
be more compact and faster. This is certainly true (by a factor of
|
||||||
~1.7x), but the resulting code would be less idiomatic and rather
|
~1.7x). Switching to a struct-of-arrays would help, too.
|
||||||
|
</p>
|
||||||
|
<p style="font-size: 8pt;">
|
||||||
|
However the resulting code would be less idiomatic and rather
|
||||||
error-prone. And it still doesn't get even close to the performance of
|
error-prone. And it still doesn't get even close to the performance of
|
||||||
the FFI version of the code. Also, high-level data structures cannot
|
the FFI version of the code. Also, high-level data structures cannot
|
||||||
be easily passed to other C functions, especially I/O functions,
|
be easily passed to other C functions, especially I/O functions,
|
||||||
|
@ -195,23 +195,10 @@ require the <tt>nelem</tt> argument. The second syntax uses a ctype as
|
|||||||
a constructor and is otherwise fully equivalent.
|
a constructor and is otherwise fully equivalent.
|
||||||
</p>
|
</p>
|
||||||
<p>
|
<p>
|
||||||
The <tt>init</tt> arguments provide optional initializers. The created
|
The cdata object is initialized according to the
|
||||||
cdata object is filled with zero bytes if no initializers are given.
|
<a href="ext_ffi_semantics.html#init">rules for initializers</a>,
|
||||||
Scalar types accept a single initializer. Aggregates can either be
|
using the optional <tt>init</tt> arguments. Excess initializers cause
|
||||||
initialized with a flat list of initializers or a single aggregate
|
an error.
|
||||||
initializer (see the <a href="ext_ffi_semantics.html#convert">C type
|
|
||||||
conversion rules</a>). Excess initializers cause an error.
|
|
||||||
</p>
|
|
||||||
<p>
|
|
||||||
If a single initializer is given for an array, it's repeated for all
|
|
||||||
remaining elements. This doesn't happen if two or more initializers
|
|
||||||
are given — all uninitialized elements are filled with zero
|
|
||||||
bytes. The fields of a <tt>struct</tt> are initialized in the order of
|
|
||||||
their declaration. Uninitialized fields are filled with zero bytes.
|
|
||||||
Only the first field of <tt>union</tt> can be initialized with a flat
|
|
||||||
initializer. Elements or fields which are aggregates themselves are
|
|
||||||
initialized with a <em>single</em> <tt>init</tt> argument, but this
|
|
||||||
may be an aggregate initializer of course.
|
|
||||||
</p>
|
</p>
|
||||||
<p>
|
<p>
|
||||||
Performance notice: if you want to create many objects of one kind,
|
Performance notice: if you want to create many objects of one kind,
|
||||||
@ -357,8 +344,8 @@ order of arguments!
|
|||||||
<h3 id="ffi_abi"><tt>status = ffi.abi(param)</tt></h3>
|
<h3 id="ffi_abi"><tt>status = ffi.abi(param)</tt></h3>
|
||||||
<p>
|
<p>
|
||||||
Returns <tt>true</tt> if <tt>param</tt> (a Lua string) applies for the
|
Returns <tt>true</tt> if <tt>param</tt> (a Lua string) applies for the
|
||||||
target ABI (Application Binary Interface). Otherwise returns
|
target ABI (Application Binary Interface). Returns <tt>false</tt>
|
||||||
<tt>false</tt>. The following parameters are currently defined:
|
otherwise. The following parameters are currently defined:
|
||||||
</p>
|
</p>
|
||||||
<table class="abitable">
|
<table class="abitable">
|
||||||
<tr class="abihead">
|
<tr class="abihead">
|
||||||
|
@ -70,6 +70,47 @@ TODO
|
|||||||
TODO
|
TODO
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
|
<h2 id="init">Initializers</h2>
|
||||||
|
<p>
|
||||||
|
Creating a cdata object with <a href="ffi_ext_api.html#ffi_new">ffi.new()</a>
|
||||||
|
or the equivalent constructor syntax always initializes its contents,
|
||||||
|
too. Different rules apply, depending on the number of optional
|
||||||
|
initializers and the C types involved:
|
||||||
|
</p>
|
||||||
|
<ul>
|
||||||
|
<li>If no initializers are given, the object is filled with zero bytes.</li>
|
||||||
|
|
||||||
|
<li>Scalar types (numbers and pointers) accept a single initializer.
|
||||||
|
The standard <a href="#convert">C type conversion rules</a>
|
||||||
|
apply.</li>
|
||||||
|
|
||||||
|
<li>Valarrays (complex numbers and vectors) are treated like scalars
|
||||||
|
when a single initializer is given. Otherwise they are treated like
|
||||||
|
regular arrays.</li>
|
||||||
|
|
||||||
|
<li>Aggregate types (arrays and structs) accept either a single
|
||||||
|
compound initializer (Lua table or string) or a flat list of
|
||||||
|
initializers.</li>
|
||||||
|
|
||||||
|
<li>The elements of an array are initialized, starting at index zero.
|
||||||
|
If a single initializer is given for an array, it's repeated for all
|
||||||
|
remaining elements. This doesn't happen if two or more initializers
|
||||||
|
are given: all remaining uninitialized elements are filled with zero
|
||||||
|
bytes.</li>
|
||||||
|
|
||||||
|
<li>The fields of a <tt>struct</tt> are initialized in the order of
|
||||||
|
their declaration. Uninitialized fields are filled with zero
|
||||||
|
bytes.</li>
|
||||||
|
|
||||||
|
<li>Only the first field of a <tt>union</tt> can be initialized with a
|
||||||
|
flat initializer.</li>
|
||||||
|
|
||||||
|
<li>Elements or fields which are aggregates themselves are initialized
|
||||||
|
with a <em>single</em> initializer, but this may be a compound
|
||||||
|
initializer or a compatible aggregate, of course.</li>
|
||||||
|
|
||||||
|
</ul>
|
||||||
|
|
||||||
<h2 id="clib">C Library Namespaces</h2>
|
<h2 id="clib">C Library Namespaces</h2>
|
||||||
<p>
|
<p>
|
||||||
A C library namespace is a special kind of object which allows
|
A C library namespace is a special kind of object which allows
|
||||||
|
@ -679,17 +679,12 @@ static void cconv_struct_init(CTState *cts, CType *d, CTSize sz, uint8_t *dp,
|
|||||||
** This is true if an aggregate is to be initialized with a value.
|
** This is true if an aggregate is to be initialized with a value.
|
||||||
** Valarrays are treated as values here so ct_tv handles (V|C, I|F).
|
** Valarrays are treated as values here so ct_tv handles (V|C, I|F).
|
||||||
*/
|
*/
|
||||||
int lj_cconv_multi_init(CTState *cts, CType *d, TValue *o)
|
int lj_cconv_multi_init(CType *d, TValue *o)
|
||||||
{
|
{
|
||||||
if (!(ctype_isrefarray(d->info) || ctype_isstruct(d->info)))
|
if (!(ctype_isrefarray(d->info) || ctype_isstruct(d->info)))
|
||||||
return 0; /* Destination is not an aggregate. */
|
return 0; /* Destination is not an aggregate. */
|
||||||
if (tvistab(o) || (tvisstr(o) && !ctype_isstruct(d->info)))
|
if (tvistab(o) || (tvisstr(o) && !ctype_isstruct(d->info)))
|
||||||
return 0; /* Initializer is not a value. */
|
return 0; /* Initializer is not a value. */
|
||||||
if (tviscdata(o)) {
|
|
||||||
CTInfo info = lj_ctype_rawref(cts, cdataV(o)->typeid)->info;
|
|
||||||
if (ctype_isrefarray(info) || ctype_isstruct(info))
|
|
||||||
return 0; /* Initializer is not a value. */
|
|
||||||
}
|
|
||||||
return 1; /* Otherwise the initializer is a value. */
|
return 1; /* Otherwise the initializer is a value. */
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -699,7 +694,7 @@ void lj_cconv_ct_init(CTState *cts, CType *d, CTSize sz,
|
|||||||
{
|
{
|
||||||
if (len == 0)
|
if (len == 0)
|
||||||
memset(dp, 0, sz);
|
memset(dp, 0, sz);
|
||||||
else if (len == 1 && !lj_cconv_multi_init(cts, d, o))
|
else if (len == 1 && !lj_cconv_multi_init(d, o))
|
||||||
lj_cconv_ct_tv(cts, d, dp, o, 0);
|
lj_cconv_ct_tv(cts, d, dp, o, 0);
|
||||||
else if (ctype_isarray(d->info)) /* Also handles valarray init with len>1. */
|
else if (ctype_isarray(d->info)) /* Also handles valarray init with len>1. */
|
||||||
cconv_array_init(cts, d, sz, dp, o, len);
|
cconv_array_init(cts, d, sz, dp, o, len);
|
||||||
|
@ -58,7 +58,7 @@ LJ_FUNC int lj_cconv_tv_bf(CTState *cts, CType *s, TValue *o, uint8_t *sp);
|
|||||||
LJ_FUNC void lj_cconv_ct_tv(CTState *cts, CType *d,
|
LJ_FUNC void lj_cconv_ct_tv(CTState *cts, CType *d,
|
||||||
uint8_t *dp, TValue *o, CTInfo flags);
|
uint8_t *dp, TValue *o, CTInfo flags);
|
||||||
LJ_FUNC void lj_cconv_bf_tv(CTState *cts, CType *d, uint8_t *dp, TValue *o);
|
LJ_FUNC void lj_cconv_bf_tv(CTState *cts, CType *d, uint8_t *dp, TValue *o);
|
||||||
LJ_FUNC int lj_cconv_multi_init(CTState *cts, CType *d, TValue *o);
|
LJ_FUNC int lj_cconv_multi_init(CType *d, TValue *o);
|
||||||
LJ_FUNC void lj_cconv_ct_init(CTState *cts, CType *d, CTSize sz,
|
LJ_FUNC void lj_cconv_ct_init(CTState *cts, CType *d, CTSize sz,
|
||||||
uint8_t *dp, TValue *o, MSize len);
|
uint8_t *dp, TValue *o, MSize len);
|
||||||
|
|
||||||
|
@ -566,8 +566,7 @@ static void crec_alloc(jit_State *J, RecordFFData *rd, CTypeID id)
|
|||||||
CType *d = ctype_raw(cts, id);
|
CType *d = ctype_raw(cts, id);
|
||||||
TRef trcd = emitir(IRTG(IR_CNEW, IRT_CDATA), trid, TREF_NIL);
|
TRef trcd = emitir(IRTG(IR_CNEW, IRT_CDATA), trid, TREF_NIL);
|
||||||
J->base[0] = trcd;
|
J->base[0] = trcd;
|
||||||
if (J->base[1] && !J->base[2] &&
|
if (J->base[1] && !J->base[2] && !lj_cconv_multi_init(d, &rd->argv[1])) {
|
||||||
!lj_cconv_multi_init(cts, d, &rd->argv[1])) {
|
|
||||||
goto single_init;
|
goto single_init;
|
||||||
} else if (ctype_isarray(d->info)) {
|
} else if (ctype_isarray(d->info)) {
|
||||||
CType *dc = ctype_rawchild(cts, d); /* Array element type. */
|
CType *dc = ctype_rawchild(cts, d); /* Array element type. */
|
||||||
|
Loading…
Reference in New Issue
Block a user