Browse Source

FFI: Simplify initializer rules. Clarify docs.

Mike Pall 14 years ago
parent
commit
72b3fff72f
6 changed files with 58 additions and 33 deletions
  1. 7 4
      doc/ext_ffi.html
  2. 6 19
      doc/ext_ffi_api.html
  3. 41 0
      doc/ext_ffi_semantics.html
  4. 2 7
      src/lj_cconv.c
  5. 1 1
      src/lj_cconv.h
  6. 1 2
      src/lj_crecord.c

+ 7 - 4
doc/ext_ffi.html

@@ -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
-via the classic Lua/C API.
+be inlined in JIT-compiled code, unlike calls to functions bound via
+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&nbsp;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&nbsp;functions, especially I/O functions,
 be easily passed to other C&nbsp;functions, especially I/O functions,

+ 6 - 19
doc/ext_ffi_api.html

@@ -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
-cdata object is filled with zero bytes if no initializers are given.
-Scalar types accept a single initializer. Aggregates can either be
-initialized with a flat list of initializers or a single aggregate
-initializer (see the <a href="ext_ffi_semantics.html#convert">C&nbsp;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 &mdash; 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.
+The cdata object is initialized according to the
+<a href="ext_ffi_semantics.html#init">rules for initializers</a>,
+using the optional <tt>init</tt> arguments. Excess initializers cause
+an error.
 </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
-<tt>false</tt>. The following parameters are currently defined:
+target ABI (Application Binary Interface). Returns <tt>false</tt>
+otherwise. The following parameters are currently defined:
 </p>
 </p>
 <table class="abitable">
 <table class="abitable">
 <tr class="abihead">
 <tr class="abihead">

+ 41 - 0
doc/ext_ffi_semantics.html

@@ -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&nbsp;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&nbsp;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&nbsp;library namespace is a special kind of object which allows
 A C&nbsp;library namespace is a special kind of object which allows

+ 2 - 7
src/lj_cconv.c

@@ -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);

+ 1 - 1
src/lj_cconv.h

@@ -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);
 
 

+ 1 - 2
src/lj_crecord.c

@@ -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] &&
-	!lj_cconv_multi_init(cts, d, &rd->argv[1])) {
+    if (J->base[1] && !J->base[2] && !lj_cconv_multi_init(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. */