Преглед на файлове

FFI: Simplify initializer rules. Clarify docs.

Mike Pall преди 14 години
родител
ревизия
72b3fff72f
променени са 6 файла, в които са добавени 58 реда и са изтрити 33 реда
  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
 accesses to C data structures from Lua code is on par with the
 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>
 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
 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
-faster than with plain Lua).
+faster than the Lua interpreter).
 </p>
 <p style="font-size: 8pt;">
 The avid reader may notice that converting the pure Lua version over
 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
 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
 the FFI version of the code. Also, high-level data structures cannot
 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.
 </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>
 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>
 <p>
 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>
 <table class="abitable">
 <tr class="abihead">

+ 41 - 0
doc/ext_ffi_semantics.html

@@ -70,6 +70,47 @@ TODO
 TODO
 </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>
 <p>
 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.
 ** 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)))
     return 0;  /* Destination is not an aggregate. */
   if (tvistab(o) || (tvisstr(o) && !ctype_isstruct(d->info)))
     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. */
 }
 
@@ -699,7 +694,7 @@ void lj_cconv_ct_init(CTState *cts, CType *d, CTSize sz,
 {
   if (len == 0)
     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);
   else if (ctype_isarray(d->info))  /* Also handles valarray init with len>1. */
     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,
 			    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 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,
 			      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);
     TRef trcd = emitir(IRTG(IR_CNEW, IRT_CDATA), trid, TREF_NIL);
     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;
     } else if (ctype_isarray(d->info)) {
       CType *dc = ctype_rawchild(cts, d);  /* Array element type. */