summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMike Pall <mike>2011-04-12 19:15:00 +0200
committerMike Pall <mike>2011-04-12 19:16:39 +0200
commit3b6f37dd2c336987251d53a4678396ef38921b3e (patch)
tree6e6176c37b600e461d078dbe663008dcc84d2418
parentfa5cd010e8e28c7fe2338d0fdd538e95ddd88bcc (diff)
downloadluajit-3b6f37dd2c336987251d53a4678396ef38921b3e.tar.gz
luajit-3b6f37dd2c336987251d53a4678396ef38921b3e.tar.bz2
luajit-3b6f37dd2c336987251d53a4678396ef38921b3e.zip
FFI: Add ctype metamethods and ffi.metatype().
-rw-r--r--doc/ext_ffi_api.html25
-rw-r--r--doc/ext_ffi_semantics.html15
-rw-r--r--doc/ext_ffi_tutorial.html93
-rw-r--r--src/Makefile.dep13
-rw-r--r--src/lib_ffi.c116
-rw-r--r--src/lj_asm.c6
-rw-r--r--src/lj_carith.c42
-rw-r--r--src/lj_cdata.c26
-rw-r--r--src/lj_crecord.c153
-rw-r--r--src/lj_ctype.c16
-rw-r--r--src/lj_ctype.h2
11 files changed, 425 insertions, 82 deletions
diff --git a/doc/ext_ffi_api.html b/doc/ext_ffi_api.html
index 5bd4b80c..2b6d1d86 100644
--- a/doc/ext_ffi_api.html
+++ b/doc/ext_ffi_api.html
@@ -238,6 +238,31 @@ This functions is mainly useful to override the pointer compatibility
238checks or to convert pointers to addresses or vice versa. 238checks or to convert pointers to addresses or vice versa.
239</p> 239</p>
240 240
241<h3 id="ffi_metatype"><tt>ctype = ffi.metatype(ct, metatable)</tt></h3>
242<p>
243Creates a ctype object for the given <tt>ct</tt> and associates it with
244a metatable. Only <tt>struct</tt>/<tt>union</tt> types, complex numbers
245and vectors are allowed. Other types may be wrapped in a
246<tt>struct</tt>, if needed.
247</p>
248<p>
249The association with a metatable is permanent and cannot be changed
250afterwards. Neither the contents of the <tt>metatable</tt> nor the
251contents of an <tt>__index</tt> table (if any) may be modified
252afterwards. The associated metatable automatically applies to all uses
253of this type, no matter how the objects are created or where they
254originate from. Note that pre-defined operations on types have
255precedence (e.g. declared field names cannot be overriden).
256</p>
257<p>
258All standard Lua metamethods are implemented. These are called directly,
259without shortcuts and on any mix of types. For binary operations, the
260left operand is checked first for a valid ctype metamethod. The
261<tt>__gc</tt> metamethod only applies to <tt>struct</tt>/<tt>union</tt>
262types and performs an implicit <a href="#ffi_gc"><tt>ffi.gc()</tt></a>
263call during creation of an instance.
264</p>
265
241<h3 id="ffi_gc"><tt>cdata = ffi.gc(cdata, finalizer)</tt></h3> 266<h3 id="ffi_gc"><tt>cdata = ffi.gc(cdata, finalizer)</tt></h3>
242<p> 267<p>
243Associates a finalizer with a pointer or aggregate cdata object. The 268Associates a finalizer with a pointer or aggregate cdata object. The
diff --git a/doc/ext_ffi_semantics.html b/doc/ext_ffi_semantics.html
index f9a118a0..d9aa27c8 100644
--- a/doc/ext_ffi_semantics.html
+++ b/doc/ext_ffi_semantics.html
@@ -582,6 +582,10 @@ Reference types are dereferenced <em>before</em> performing each of
582the operations below &mdash; the operation is applied to the 582the operations below &mdash; the operation is applied to the
583C&nbsp;type pointed to by the reference. 583C&nbsp;type pointed to by the reference.
584</p> 584</p>
585<p>
586The pre-defined operations are always tried first before deferring to a
587metamethod for a ctype (if defined).
588</p>
585 589
586<h3 id="cdata_array">Indexing a cdata object</h3> 590<h3 id="cdata_array">Indexing a cdata object</h3>
587<ul> 591<ul>
@@ -803,9 +807,10 @@ vararg functions</a>.
803</p> 807</p>
804<p> 808<p>
805Memory areas returned by C functions (e.g. from <tt>malloc()</tt>) 809Memory areas returned by C functions (e.g. from <tt>malloc()</tt>)
806must be manually managed, of course. Pointers to cdata objects are 810must be manually managed, of course (or use
807indistinguishable from pointers returned by C functions (which is one 811<a href="ext_ffi_api.html#ffi_gc"><tt>ffi.gc()</tt></a>)). Pointers to
808of the reasons why the GC cannot follow them). 812cdata objects are indistinguishable from pointers returned by C
813functions (which is one of the reasons why the GC cannot follow them).
809</p> 814</p>
810 815
811<h2 id="clib">C Library Namespaces</h2> 816<h2 id="clib">C Library Namespaces</h2>
@@ -977,6 +982,9 @@ two.</li>
977value.</li> 982value.</li>
978<li>Calls to C&nbsp;functions with 64 bit arguments or return values 983<li>Calls to C&nbsp;functions with 64 bit arguments or return values
979on 32 bit CPUs.</li> 984on 32 bit CPUs.</li>
985<li>Calls to ctype metamethods which are not plain functions.</li>
986<li>ctype <tt>__newindex</tt> tables and non-string lookups in ctype
987<tt>__index</tt> tables.</li>
980<li>Accesses to external variables in C&nbsp;library namespaces.</li> 988<li>Accesses to external variables in C&nbsp;library namespaces.</li>
981<li><tt>tostring()</tt> for cdata types.</li> 989<li><tt>tostring()</tt> for cdata types.</li>
982<li>The following <a href="ext_ffi_api.html">ffi.* API</a> functions: 990<li>The following <a href="ext_ffi_api.html">ffi.* API</a> functions:
@@ -988,7 +996,6 @@ Other missing features:
988<ul> 996<ul>
989<li>Bit operations for 64&nbsp;bit types.</li> 997<li>Bit operations for 64&nbsp;bit types.</li>
990<li>Arithmetic for <tt>complex</tt> numbers.</li> 998<li>Arithmetic for <tt>complex</tt> numbers.</li>
991<li>User-defined metamethods for C&nbsp;types.</li>
992<li>Callbacks from C&nbsp;code to Lua functions.</li> 999<li>Callbacks from C&nbsp;code to Lua functions.</li>
993<li>Atomic handling of <tt>errno</tt>.</li> 1000<li>Atomic handling of <tt>errno</tt>.</li>
994<li>Passing structs by value to vararg C&nbsp;functions.</li> 1001<li>Passing structs by value to vararg C&nbsp;functions.</li>
diff --git a/doc/ext_ffi_tutorial.html b/doc/ext_ffi_tutorial.html
index 38126865..d5b04bc6 100644
--- a/doc/ext_ffi_tutorial.html
+++ b/doc/ext_ffi_tutorial.html
@@ -386,6 +386,99 @@ application might work on some systems, but would fail in a POSIX/x64
386environment. 386environment.
387</p> 387</p>
388 388
389<h2 id="metatype">Defining Metamethods for a C&nbsp;Type</h2>
390<p>
391The following code explains how to define metamethods for a C type.
392We define a simple point type and add some operations to it:
393</p>
394<pre class="code mark">
395<span class="codemark">&nbsp;
396&#9312;
397
398
399
400&#9313;
401
402&#9314;
403
404&#9315;
405
406
407
408&#9316;
409
410&#9317;</span>local ffi = require("ffi")
411ffi.cdef[[
412<span style="color:#00a000;">typedef struct { double x, y; } point_t;</span>
413]]
414
415local point
416local mt = {
417 __add = function(a, b) return point(a.x+b.x, a.y+b.y) end,
418 __len = function(a) return math.sqrt(a.x*a.x + a.y*a.y) end,
419 __index = {
420 area = function(a) return a.x*a.x + a.y*a.y end,
421 },
422}
423point = ffi.metatype("point_t", mt)
424
425local a = point(3, 4)
426print(a.x, a.y) --> 3 4
427print(#a) --> 5
428print(a:area()) --> 25
429local b = a + point(0.5, 8)
430print(#b) --> 12.5
431</pre>
432<p>
433Here's the step-by-step explanation:
434</p>
435<p>
436<span class="mark">&#9312;</span> This defines the C&nbsp;type for a
437two-dimensional point object.
438</p>
439<p>
440<span class="mark">&#9313;</span> We have to declare the variable
441holding the point constructor first, because it's used inside of a
442metamethod.
443</p>
444<p>
445<span class="mark">&#9314;</span> Let's define an <tt>__add</tt>
446metamethod which adds the coordinates of two points and creates a new
447point object. For simplicity, this function assumes that both arguments
448are points. But it could be any mix of objects, if at least one operand
449is of the required type (e.g. adding a point plus a number or vice
450versa). Our <tt>__len</tt> metamethod returns the distance of a point to
451the origin.
452</p>
453<p>
454<span class="mark">&#9315;</span> If we run out of operators, we can
455define named methods, too. Here the <tt>__index</tt> table defines an
456<tt>area</tt> function. For custom indexing needs, one might want to
457define <tt>__index</tt> and <tt>__newindex</tt> functions instead.
458</p>
459<p>
460<span class="mark">&#9316;</span> This associates the metamethods with
461our C&nbsp;type. This only needs to be done once. For convenience, a
462constructor is returned by
463<a href="ffi_ext_api.html#ffi_metatype"><tt>ffi.metatype()</tt></a>.
464We're not required to use it, though. The original C&nbsp;type can still
465be used e.g. to create an array of points. The metamethods automatically
466apply to any and all uses of this type.
467</p>
468<p>
469Please note that the association with a metatable is permanent and
470<b>the metatable must not be modified afterwards!</b> Ditto for the
471<tt>__index</tt> table.
472</p>
473<p>
474<span class="mark">&#9317;</span> Here are some simple usage examples
475for the point type and their expected results. The pre-defined
476operations (such as <tt>a.x</tt>) can be freely mixed with the newly
477defined metamethods. Note that <tt>area</tt> is a method and must be
478called with the Lua syntax for methods: <tt>a:area()</tt>, not
479<tt>a.area()</tt>.
480</p>
481
389<h2 id="idioms">Translating C&nbsp;Idioms</h2> 482<h2 id="idioms">Translating C&nbsp;Idioms</h2>
390<p> 483<p>
391Here's a list of common C&nbsp;idioms and their translation to the 484Here's a list of common C&nbsp;idioms and their translation to the
diff --git a/src/Makefile.dep b/src/Makefile.dep
index 57904877..c06060ce 100644
--- a/src/Makefile.dep
+++ b/src/Makefile.dep
@@ -21,9 +21,9 @@ lib_bit.o: lib_bit.c lua.h luaconf.h lauxlib.h lualib.h lj_obj.h lj_def.h \
21lib_debug.o: lib_debug.c lua.h luaconf.h lauxlib.h lualib.h lj_obj.h \ 21lib_debug.o: lib_debug.c lua.h luaconf.h lauxlib.h lualib.h lj_obj.h \
22 lj_def.h lj_arch.h lj_err.h lj_errmsg.h lj_lib.h lj_libdef.h 22 lj_def.h lj_arch.h lj_err.h lj_errmsg.h lj_lib.h lj_libdef.h
23lib_ffi.o: lib_ffi.c lua.h luaconf.h lauxlib.h lualib.h lj_obj.h lj_def.h \ 23lib_ffi.o: lib_ffi.c lua.h luaconf.h lauxlib.h lualib.h lj_obj.h lj_def.h \
24 lj_arch.h lj_gc.h lj_err.h lj_errmsg.h lj_str.h lj_tab.h lj_ctype.h \ 24 lj_arch.h lj_gc.h lj_err.h lj_errmsg.h lj_str.h lj_tab.h lj_meta.h \
25 lj_cparse.h lj_cdata.h lj_cconv.h lj_carith.h lj_ccall.h lj_clib.h \ 25 lj_ctype.h lj_cparse.h lj_cdata.h lj_cconv.h lj_carith.h lj_ccall.h \
26 lj_ff.h lj_ffdef.h lj_lib.h lj_libdef.h 26 lj_clib.h lj_ff.h lj_ffdef.h lj_lib.h lj_libdef.h
27lib_init.o: lib_init.c lua.h luaconf.h lauxlib.h lualib.h lj_arch.h 27lib_init.o: lib_init.c lua.h luaconf.h lauxlib.h lualib.h lj_arch.h
28lib_io.o: lib_io.c lua.h luaconf.h lauxlib.h lualib.h lj_obj.h lj_def.h \ 28lib_io.o: lib_io.c lua.h luaconf.h lauxlib.h lualib.h lj_obj.h lj_def.h \
29 lj_arch.h lj_gc.h lj_err.h lj_errmsg.h lj_str.h lj_ff.h lj_ffdef.h \ 29 lj_arch.h lj_gc.h lj_err.h lj_errmsg.h lj_str.h lj_ff.h lj_ffdef.h \
@@ -57,8 +57,8 @@ lj_asm.o: lj_asm.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.h lj_gc.h \
57lj_bc.o: lj_bc.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.h lj_bc.h \ 57lj_bc.o: lj_bc.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.h lj_bc.h \
58 lj_bcdef.h 58 lj_bcdef.h
59lj_carith.o: lj_carith.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.h \ 59lj_carith.o: lj_carith.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.h \
60 lj_gc.h lj_err.h lj_errmsg.h lj_ctype.h lj_cconv.h lj_cdata.h \ 60 lj_gc.h lj_err.h lj_errmsg.h lj_tab.h lj_meta.h lj_ctype.h lj_cconv.h \
61 lj_carith.h 61 lj_cdata.h lj_carith.h
62lj_ccall.o: lj_ccall.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.h \ 62lj_ccall.o: lj_ccall.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.h \
63 lj_gc.h lj_err.h lj_errmsg.h lj_str.h lj_ctype.h lj_cconv.h lj_cdata.h \ 63 lj_gc.h lj_err.h lj_errmsg.h lj_str.h lj_ctype.h lj_cconv.h lj_cdata.h \
64 lj_ccall.h lj_trace.h lj_jit.h lj_ir.h lj_dispatch.h lj_bc.h \ 64 lj_ccall.h lj_trace.h lj_jit.h lj_ir.h lj_dispatch.h lj_bc.h \
@@ -77,7 +77,8 @@ lj_cparse.o: lj_cparse.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.h \
77lj_crecord.o: lj_crecord.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.h \ 77lj_crecord.o: lj_crecord.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.h \
78 lj_err.h lj_errmsg.h lj_str.h lj_tab.h lj_frame.h lj_bc.h lj_ctype.h \ 78 lj_err.h lj_errmsg.h lj_str.h lj_tab.h lj_frame.h lj_bc.h lj_ctype.h \
79 lj_gc.h lj_cparse.h lj_cconv.h lj_clib.h lj_ir.h lj_jit.h lj_iropt.h \ 79 lj_gc.h lj_cparse.h lj_cconv.h lj_clib.h lj_ir.h lj_jit.h lj_iropt.h \
80 lj_trace.h lj_dispatch.h lj_traceerr.h lj_ffrecord.h lj_crecord.h 80 lj_trace.h lj_dispatch.h lj_traceerr.h lj_record.h lj_ffrecord.h \
81 lj_crecord.h
81lj_ctype.o: lj_ctype.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.h \ 82lj_ctype.o: lj_ctype.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.h \
82 lj_gc.h lj_err.h lj_errmsg.h lj_str.h lj_tab.h lj_ctype.h 83 lj_gc.h lj_err.h lj_errmsg.h lj_str.h lj_tab.h lj_ctype.h
83lj_dispatch.o: lj_dispatch.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.h \ 84lj_dispatch.o: lj_dispatch.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.h \
diff --git a/src/lib_ffi.c b/src/lib_ffi.c
index cb001ae9..fe84ca7d 100644
--- a/src/lib_ffi.c
+++ b/src/lib_ffi.c
@@ -18,6 +18,7 @@
18#include "lj_err.h" 18#include "lj_err.h"
19#include "lj_str.h" 19#include "lj_str.h"
20#include "lj_tab.h" 20#include "lj_tab.h"
21#include "lj_meta.h"
21#include "lj_ctype.h" 22#include "lj_ctype.h"
22#include "lj_cparse.h" 23#include "lj_cparse.h"
23#include "lj_cdata.h" 24#include "lj_cdata.h"
@@ -96,6 +97,41 @@ static int32_t ffi_checkint(lua_State *L, int narg)
96 97
97#define LJLIB_MODULE_ffi_meta 98#define LJLIB_MODULE_ffi_meta
98 99
100/* Handle ctype __index/__newindex metamethods. */
101static int ffi_index_meta(lua_State *L, CTState *cts, CType *ct, MMS mm)
102{
103 CTypeID id = ctype_typeid(cts, ct);
104 cTValue *tv = lj_ctype_meta(cts, id, mm);
105 TValue *base = L->base;
106 if (!tv) {
107 const char *s;
108 err_index:
109 s = strdata(lj_ctype_repr(L, id, NULL));
110 if (tvisstr(L->base+1))
111 lj_err_callerv(L, LJ_ERR_FFI_BADMEMBER, s, strVdata(L->base+1));
112 else
113 lj_err_callerv(L, LJ_ERR_FFI_BADIDX, s);
114 }
115 if (!tvisfunc(tv)) {
116 if (mm == MM_index) {
117 cTValue *o = lj_meta_tget(L, tv, base+1);
118 if (o) {
119 if (tvisnil(o)) goto err_index;
120 copyTV(L, L->top-1, o);
121 return 1;
122 }
123 } else {
124 TValue *o = lj_meta_tset(L, tv, base+1);
125 if (o) {
126 copyTV(L, o, base+2);
127 return 0;
128 }
129 }
130 tv = L->top-1;
131 }
132 return lj_meta_tailcall(L, tv);
133}
134
99LJLIB_CF(ffi_meta___index) LJLIB_REC(cdata_index 0) 135LJLIB_CF(ffi_meta___index) LJLIB_REC(cdata_index 0)
100{ 136{
101 CTState *cts = ctype_cts(L); 137 CTState *cts = ctype_cts(L);
@@ -106,6 +142,8 @@ LJLIB_CF(ffi_meta___index) LJLIB_REC(cdata_index 0)
106 if (!(o+1 < L->top && tviscdata(o))) /* Also checks for presence of key. */ 142 if (!(o+1 < L->top && tviscdata(o))) /* Also checks for presence of key. */
107 lj_err_argt(L, 1, LUA_TCDATA); 143 lj_err_argt(L, 1, LUA_TCDATA);
108 ct = lj_cdata_index(cts, cdataV(o), o+1, &p, &qual); 144 ct = lj_cdata_index(cts, cdataV(o), o+1, &p, &qual);
145 if ((qual & 1))
146 return ffi_index_meta(L, cts, ct, MM_index);
109 if (lj_cdata_get(cts, ct, L->top-1, p)) 147 if (lj_cdata_get(cts, ct, L->top-1, p))
110 lj_gc_check(L); 148 lj_gc_check(L);
111 return 1; 149 return 1;
@@ -121,6 +159,11 @@ LJLIB_CF(ffi_meta___newindex) LJLIB_REC(cdata_index 1)
121 if (!(o+2 < L->top && tviscdata(o))) /* Also checks for key and value. */ 159 if (!(o+2 < L->top && tviscdata(o))) /* Also checks for key and value. */
122 lj_err_argt(L, 1, LUA_TCDATA); 160 lj_err_argt(L, 1, LUA_TCDATA);
123 ct = lj_cdata_index(cts, cdataV(o), o+1, &p, &qual); 161 ct = lj_cdata_index(cts, cdataV(o), o+1, &p, &qual);
162 if ((qual & 1)) {
163 if ((qual & CTF_CONST))
164 lj_err_caller(L, LJ_ERR_FFI_WRCONST);
165 return ffi_index_meta(L, cts, ct, MM_newindex);
166 }
124 lj_cdata_set(cts, ct, p, o+2, qual); 167 lj_cdata_set(cts, ct, p, o+2, qual);
125 return 0; 168 return 0;
126} 169}
@@ -138,7 +181,7 @@ LJLIB_CF(ffi_meta___eq) LJLIB_REC(cdata_arith MM_eq)
138 return ffi_arith(L); 181 return ffi_arith(L);
139} 182}
140 183
141LJLIB_CF(ffi_meta___len) 184LJLIB_CF(ffi_meta___len) LJLIB_REC(cdata_arith MM_len)
142{ 185{
143 return ffi_arith(L); 186 return ffi_arith(L);
144} 187}
@@ -153,11 +196,21 @@ LJLIB_CF(ffi_meta___le) LJLIB_REC(cdata_arith MM_le)
153 return ffi_arith(L); 196 return ffi_arith(L);
154} 197}
155 198
156LJLIB_CF(ffi_meta___concat) 199LJLIB_CF(ffi_meta___concat) LJLIB_REC(cdata_arith MM_concat)
157{ 200{
158 return ffi_arith(L); 201 return ffi_arith(L);
159} 202}
160 203
204/* Handle ctype __call metamethod. */
205static int ffi_call_meta(lua_State *L, CTypeID id)
206{
207 CTState *cts = ctype_cts(L);
208 cTValue *tv = lj_ctype_meta(cts, id, MM_call);
209 if (!tv)
210 lj_err_callerv(L, LJ_ERR_FFI_BADCALL, strdata(lj_ctype_repr(L, id, NULL)));
211 return lj_meta_tailcall(L, tv);
212}
213
161/* Forward declaration. */ 214/* Forward declaration. */
162static int lj_cf_ffi_new(lua_State *L); 215static int lj_cf_ffi_new(lua_State *L);
163 216
@@ -168,8 +221,7 @@ LJLIB_CF(ffi_meta___call) LJLIB_REC(cdata_call)
168 if (cd->typeid == CTID_CTYPEID) 221 if (cd->typeid == CTID_CTYPEID)
169 return lj_cf_ffi_new(L); 222 return lj_cf_ffi_new(L);
170 if ((ret = lj_ccall_func(L, cd)) < 0) 223 if ((ret = lj_ccall_func(L, cd)) < 0)
171 lj_err_callerv(L, LJ_ERR_FFI_BADCALL, 224 return ffi_call_meta(L, cd->typeid);
172 strdata(lj_ctype_repr(L, cd->typeid, NULL)));
173 return ret; 225 return ret;
174} 226}
175 227
@@ -226,6 +278,12 @@ LJLIB_CF(ffi_meta___tostring)
226 setstrV(L, L->top-1, lj_ctype_repr_int64(L, *(uint64_t *)cdataptr(cd), 278 setstrV(L, L->top-1, lj_ctype_repr_int64(L, *(uint64_t *)cdataptr(cd),
227 (ct->info & CTF_UNSIGNED))); 279 (ct->info & CTF_UNSIGNED)));
228 goto checkgc; 280 goto checkgc;
281 } else if (ctype_isstruct(ct->info) || ctype_isvector(ct->info)) {
282 /* Handle ctype __tostring metamethod. */
283 CTState *cts = ctype_cts(L);
284 cTValue *tv = lj_ctype_meta(cts, id, MM_tostring);
285 if (tv)
286 return lj_meta_tailcall(L, tv);
229 } 287 }
230 } 288 }
231 lj_str_pushf(L, msg, strdata(lj_ctype_repr(L, id, NULL)), cdataptr(cd)); 289 lj_str_pushf(L, msg, strdata(lj_ctype_repr(L, id, NULL)), cdataptr(cd));
@@ -234,6 +292,8 @@ checkgc:
234 return 1; 292 return 1;
235} 293}
236 294
295LJLIB_PUSH("ffi") LJLIB_SET(__metatable)
296
237#include "lj_libdef.h" 297#include "lj_libdef.h"
238 298
239/* -- C library metamethods ----------------------------------------------- */ 299/* -- C library metamethods ----------------------------------------------- */
@@ -331,14 +391,14 @@ LJLIB_CF(ffi_new) LJLIB_REC(.)
331{ 391{
332 CTState *cts = ctype_cts(L); 392 CTState *cts = ctype_cts(L);
333 CTypeID id = ffi_checkctype(L, cts); 393 CTypeID id = ffi_checkctype(L, cts);
394 CType *ct = ctype_raw(cts, id);
334 CTSize sz; 395 CTSize sz;
335 CTInfo info = lj_ctype_info(cts, id, &sz); 396 CTInfo info = lj_ctype_info(cts, id, &sz);
336 TValue *o = L->base+1; 397 TValue *o = L->base+1;
337 GCcdata *cd; 398 GCcdata *cd;
338 if ((info & CTF_VLA)) { 399 if ((info & CTF_VLA)) {
339 o++; 400 o++;
340 sz = lj_ctype_vlsize(cts, ctype_raw(cts, id), 401 sz = lj_ctype_vlsize(cts, ct, (CTSize)ffi_checkint(L, 2));
341 (CTSize)ffi_checkint(L, 2));
342 } 402 }
343 if (sz == CTSIZE_INVALID) 403 if (sz == CTSIZE_INVALID)
344 lj_err_arg(L, 1, LJ_ERR_FFI_INVSIZE); 404 lj_err_arg(L, 1, LJ_ERR_FFI_INVSIZE);
@@ -347,8 +407,21 @@ LJLIB_CF(ffi_new) LJLIB_REC(.)
347 else 407 else
348 cd = lj_cdata_newv(cts, id, sz, ctype_align(info)); 408 cd = lj_cdata_newv(cts, id, sz, ctype_align(info));
349 setcdataV(L, o-1, cd); /* Anchor the uninitialized cdata. */ 409 setcdataV(L, o-1, cd); /* Anchor the uninitialized cdata. */
350 lj_cconv_ct_init(cts, ctype_raw(cts, id), sz, cdataptr(cd), 410 lj_cconv_ct_init(cts, ct, sz, cdataptr(cd),
351 o, (MSize)(L->top - o)); /* Initialize cdata. */ 411 o, (MSize)(L->top - o)); /* Initialize cdata. */
412 if (ctype_isstruct(ct->info)) {
413 /* Handle ctype __gc metamethod. Use the fast lookup here. */
414 cTValue *tv = lj_tab_getint(cts->metatype, (int32_t)id);
415 if (tv && tvistab(tv) && (tv = lj_meta_fast(L, tabV(tv), MM_gc))) {
416 GCtab *t = cts->finalizer;
417 if (gcref(t->metatable)) {
418 /* Add to finalizer table, if still enabled. */
419 copyTV(L, lj_tab_set(L, t, o-1), tv);
420 lj_gc_anybarriert(L, t);
421 cd->marked |= LJ_GC_CDATA_FIN;
422 }
423 }
424 }
352 L->top = o; /* Only return the cdata itself. */ 425 L->top = o; /* Only return the cdata itself. */
353 lj_gc_check(L); 426 lj_gc_check(L);
354 return 1; 427 return 1;
@@ -521,7 +594,33 @@ LJLIB_CF(ffi_abi) LJLIB_REC(.)
521 594
522#undef H_ 595#undef H_
523 596
524LJLIB_PUSH(top-7) LJLIB_SET(!) /* Store reference to weak table. */ 597LJLIB_PUSH(top-8) LJLIB_SET(!) /* Store reference to metatype table. */
598
599LJLIB_CF(ffi_metatype)
600{
601 CTState *cts = ctype_cts(L);
602 CTypeID id = ffi_checkctype(L, cts);
603 GCtab *mt = lj_lib_checktab(L, 2);
604 GCtab *t = cts->metatype;
605 CType *ct = ctype_get(cts, id); /* Only allow raw types. */
606 TValue *tv;
607 GCcdata *cd;
608 if (!(ctype_isstruct(ct->info) || ctype_iscomplex(ct->info) ||
609 ctype_isvector(ct->info)))
610 lj_err_arg(L, 1, LJ_ERR_FFI_INVTYPE);
611 tv = lj_tab_setint(L, t, (int32_t)id);
612 if (!tvisnil(tv))
613 lj_err_caller(L, LJ_ERR_PROTMT);
614 settabV(L, tv, mt);
615 lj_gc_anybarriert(L, t);
616 cd = lj_cdata_new(cts, CTID_CTYPEID, 4);
617 *(CTypeID *)cdataptr(cd) = id;
618 setcdataV(L, L->top-1, cd);
619 lj_gc_check(L);
620 return 1;
621}
622
623LJLIB_PUSH(top-7) LJLIB_SET(!) /* Store reference to finalizer table. */
525 624
526LJLIB_CF(ffi_gc) 625LJLIB_CF(ffi_gc)
527{ 626{
@@ -590,6 +689,7 @@ static void ffi_register_module(lua_State *L)
590LUALIB_API int luaopen_ffi(lua_State *L) 689LUALIB_API int luaopen_ffi(lua_State *L)
591{ 690{
592 CTState *cts = lj_ctype_init(L); 691 CTState *cts = lj_ctype_init(L);
692 settabV(L, L->top++, (cts->metatype = lj_tab_new(L, 0, 0)));
593 cts->finalizer = ffi_finalizer(L); 693 cts->finalizer = ffi_finalizer(L);
594 LJ_LIB_REG(L, NULL, ffi_meta); 694 LJ_LIB_REG(L, NULL, ffi_meta);
595 /* NOBARRIER: basemt is a GC root. */ 695 /* NOBARRIER: basemt is a GC root. */
diff --git a/src/lj_asm.c b/src/lj_asm.c
index a69f4461..8e7c98ee 100644
--- a/src/lj_asm.c
+++ b/src/lj_asm.c
@@ -2558,6 +2558,7 @@ static void asm_cnew(ASMState *as, IRIns *ir)
2558 lj_ctype_size(cts, typeid) : (CTSize)IR(ir->op2)->i; 2558 lj_ctype_size(cts, typeid) : (CTSize)IR(ir->op2)->i;
2559 const CCallInfo *ci = &lj_ir_callinfo[IRCALL_lj_mem_newgco]; 2559 const CCallInfo *ci = &lj_ir_callinfo[IRCALL_lj_mem_newgco];
2560 IRRef args[2]; 2560 IRRef args[2];
2561 int gcfin = 0;
2561 lua_assert(sz != CTSIZE_INVALID); 2562 lua_assert(sz != CTSIZE_INVALID);
2562 2563
2563 args[0] = ASMREF_L; /* lua_State *L */ 2564 args[0] = ASMREF_L; /* lua_State *L */
@@ -2604,12 +2605,15 @@ static void asm_cnew(ASMState *as, IRIns *ir)
2604 } while (1); 2605 } while (1);
2605#endif 2606#endif
2606 lua_assert(sz == 4 || (sz == 8 && (LJ_64 || LJ_HASFFI))); 2607 lua_assert(sz == 4 || (sz == 8 && (LJ_64 || LJ_HASFFI)));
2608 } else {
2609 if (lj_ctype_meta(cts, typeid, MM_gc) != NULL)
2610 gcfin = LJ_GC_CDATA_FIN;
2607 } 2611 }
2608 2612
2609 /* Combine initialization of marked, gct and typeid. */ 2613 /* Combine initialization of marked, gct and typeid. */
2610 emit_movtomro(as, RID_ECX, RID_RET, offsetof(GCcdata, marked)); 2614 emit_movtomro(as, RID_ECX, RID_RET, offsetof(GCcdata, marked));
2611 emit_gri(as, XG_ARITHi(XOg_OR), RID_ECX, 2615 emit_gri(as, XG_ARITHi(XOg_OR), RID_ECX,
2612 (int32_t)((~LJ_TCDATA<<8)+(typeid<<16))); 2616 (int32_t)((~LJ_TCDATA<<8)+(typeid<<16)+gcfin));
2613 emit_gri(as, XG_ARITHi(XOg_AND), RID_ECX, LJ_GC_WHITES); 2617 emit_gri(as, XG_ARITHi(XOg_AND), RID_ECX, LJ_GC_WHITES);
2614 emit_opgl(as, XO_MOVZXb, RID_ECX, gc.currentwhite); 2618 emit_opgl(as, XO_MOVZXb, RID_ECX, gc.currentwhite);
2615 2619
diff --git a/src/lj_carith.c b/src/lj_carith.c
index a59665d8..8f644d83 100644
--- a/src/lj_carith.c
+++ b/src/lj_carith.c
@@ -9,6 +9,8 @@
9 9
10#include "lj_gc.h" 10#include "lj_gc.h"
11#include "lj_err.h" 11#include "lj_err.h"
12#include "lj_tab.h"
13#include "lj_meta.h"
12#include "lj_ctype.h" 14#include "lj_ctype.h"
13#include "lj_cconv.h" 15#include "lj_cconv.h"
14#include "lj_cdata.h" 16#include "lj_cdata.h"
@@ -187,24 +189,20 @@ static int carith_int64(lua_State *L, CTState *cts, CDArith *ca, MMS mm)
187 return 0; 189 return 0;
188} 190}
189 191
190/* Arithmetic operators for cdata. */ 192/* Handle ctype arithmetic metamethods. */
191int lj_carith_op(lua_State *L, MMS mm) 193static int lj_carith_meta(lua_State *L, CTState *cts, CDArith *ca, MMS mm)
192{ 194{
193 CTState *cts = ctype_cts(L); 195 cTValue *tv = NULL;
194 CDArith ca; 196 if (tviscdata(L->base))
195 if (carith_checkarg(L, cts, &ca)) { 197 tv = lj_ctype_meta(cts, cdataV(L->base)->typeid, mm);
196 if (carith_int64(L, cts, &ca, mm) || carith_ptr(L, cts, &ca, mm)) { 198 if (!tv && L->base+1 < L->top && tviscdata(L->base+1))
197 copyTV(L, &G(L)->tmptv2, L->top-1); /* Remember for trace recorder. */ 199 tv = lj_ctype_meta(cts, cdataV(L->base+1)->typeid, mm);
198 return 1; 200 if (!tv) {
199 }
200 }
201 /* NYI: per-cdata metamethods. */
202 {
203 const char *repr[2]; 201 const char *repr[2];
204 int i; 202 int i;
205 for (i = 0; i < 2; i++) { 203 for (i = 0; i < 2; i++) {
206 if (ca.ct[i]) 204 if (ca->ct[i])
207 repr[i] = strdata(lj_ctype_repr(L, ctype_typeid(cts, ca.ct[i]), NULL)); 205 repr[i] = strdata(lj_ctype_repr(L, ctype_typeid(cts, ca->ct[i]), NULL));
208 else 206 else
209 repr[i] = typename(&L->base[i]); 207 repr[i] = typename(&L->base[i]);
210 } 208 }
@@ -213,7 +211,21 @@ int lj_carith_op(lua_State *L, MMS mm)
213 mm < MM_add ? LJ_ERR_FFI_BADCOMP : LJ_ERR_FFI_BADARITH, 211 mm < MM_add ? LJ_ERR_FFI_BADCOMP : LJ_ERR_FFI_BADARITH,
214 repr[0], repr[1]); 212 repr[0], repr[1]);
215 } 213 }
216 return 0; /* unreachable */ 214 return lj_meta_tailcall(L, tv);
215}
216
217/* Arithmetic operators for cdata. */
218int lj_carith_op(lua_State *L, MMS mm)
219{
220 CTState *cts = ctype_cts(L);
221 CDArith ca;
222 if (carith_checkarg(L, cts, &ca)) {
223 if (carith_int64(L, cts, &ca, mm) || carith_ptr(L, cts, &ca, mm)) {
224 copyTV(L, &G(L)->tmptv2, L->top-1); /* Remember for trace recorder. */
225 return 1;
226 }
227 }
228 return lj_carith_meta(L, cts, &ca, mm);
217} 229}
218 230
219/* -- 64 bit integer arithmetic helpers ----------------------------------- */ 231/* -- 64 bit integer arithmetic helpers ----------------------------------- */
diff --git a/src/lj_cdata.c b/src/lj_cdata.c
index 11c84d8e..53605e7e 100644
--- a/src/lj_cdata.c
+++ b/src/lj_cdata.c
@@ -129,13 +129,7 @@ collect_attrib:
129 } 129 }
130 } else if (tvisstr(key)) { /* String key. */ 130 } else if (tvisstr(key)) { /* String key. */
131 GCstr *name = strV(key); 131 GCstr *name = strV(key);
132 if (ctype_isptr(ct->info)) { /* Automatically perform '->'. */ 132 if (ctype_isstruct(ct->info)) {
133 if (ctype_isstruct(ctype_rawchild(cts, ct)->info)) {
134 p = (uint8_t *)cdata_getptr(p, ct->size);
135 ct = ctype_child(cts, ct);
136 goto collect_attrib;
137 }
138 } if (ctype_isstruct(ct->info)) {
139 CTSize ofs; 133 CTSize ofs;
140 CType *fct = lj_ctype_getfield(cts, ct, name, &ofs); 134 CType *fct = lj_ctype_getfield(cts, ct, name, &ofs);
141 if (fct) { 135 if (fct) {
@@ -155,7 +149,7 @@ collect_attrib:
155 } 149 }
156 } else if (cd->typeid == CTID_CTYPEID) { 150 } else if (cd->typeid == CTID_CTYPEID) {
157 /* Allow indexing a (pointer to) struct constructor to get constants. */ 151 /* Allow indexing a (pointer to) struct constructor to get constants. */
158 CType *sct = ct = ctype_raw(cts, *(CTypeID *)p); 152 CType *sct = ctype_raw(cts, *(CTypeID *)p);
159 if (ctype_isptr(sct->info)) 153 if (ctype_isptr(sct->info))
160 sct = ctype_rawchild(cts, sct); 154 sct = ctype_rawchild(cts, sct);
161 if (ctype_isstruct(sct->info)) { 155 if (ctype_isstruct(sct->info)) {
@@ -165,16 +159,16 @@ collect_attrib:
165 return fct; 159 return fct;
166 } 160 }
167 } 161 }
168 {
169 GCstr *s = lj_ctype_repr(cts->L, ctype_typeid(cts, ct), NULL);
170 lj_err_callerv(cts->L, LJ_ERR_FFI_BADMEMBER, strdata(s), strdata(name));
171 }
172 } 162 }
173 { 163 if (ctype_isptr(ct->info)) { /* Automatically perform '->'. */
174 GCstr *s = lj_ctype_repr(cts->L, ctype_typeid(cts, ct), NULL); 164 if (ctype_isstruct(ctype_rawchild(cts, ct)->info)) {
175 lj_err_callerv(cts->L, LJ_ERR_FFI_BADIDX, strdata(s)); 165 p = (uint8_t *)cdata_getptr(p, ct->size);
166 ct = ctype_child(cts, ct);
167 goto collect_attrib;
168 }
176 } 169 }
177 return NULL; /* unreachable */ 170 *qual |= 1; /* Lookup failed. */
171 return ct; /* But return the resolved raw type. */
178} 172}
179 173
180/* -- C data getters ------------------------------------------------------ */ 174/* -- C data getters ------------------------------------------------------ */
diff --git a/src/lj_crecord.c b/src/lj_crecord.c
index 0c4f5ca4..04c962d5 100644
--- a/src/lj_crecord.c
+++ b/src/lj_crecord.c
@@ -22,6 +22,7 @@
22#include "lj_jit.h" 22#include "lj_jit.h"
23#include "lj_iropt.h" 23#include "lj_iropt.h"
24#include "lj_trace.h" 24#include "lj_trace.h"
25#include "lj_record.h"
25#include "lj_ffrecord.h" 26#include "lj_ffrecord.h"
26#include "lj_crecord.h" 27#include "lj_crecord.h"
27#include "lj_dispatch.h" 28#include "lj_dispatch.h"
@@ -459,6 +460,41 @@ static TRef crec_reassoc_ofs(jit_State *J, TRef tr, ptrdiff_t *ofsp, MSize sz)
459 return tr; 460 return tr;
460} 461}
461 462
463/* Record ctype __index/__newindex metamethods. */
464static void crec_index_meta(jit_State *J, CTState *cts, CType *ct,
465 RecordFFData *rd)
466{
467 CTypeID id = ctype_typeid(cts, ct);
468 cTValue *tv = lj_ctype_meta(cts, id, rd->data ? MM_newindex : MM_index);
469 if (!tv)
470 lj_trace_err(J, LJ_TRERR_BADTYPE);
471 if (tvisfunc(tv)) {
472 J->base[-1] = lj_ir_kfunc(J, funcV(tv)) | TREF_FRAME;
473 rd->nres = -1; /* Pending tailcall. */
474 } else if (rd->data == 0 && tvistab(tv) && tref_isstr(J->base[1])) {
475 /* Specialize to result of __index lookup. */
476 cTValue *o = lj_tab_get(J->L, tabV(tv), &rd->argv[1]);
477 IRType t = itype2irt(o);
478 if (tvisgcv(o))
479 J->base[0] = lj_ir_kgc(J, gcV(o), t);
480 else if (tvisint(o))
481 J->base[0] = lj_ir_kint(J, intV(o));
482 else if (tvisnum(o))
483 J->base[0] = lj_ir_knumint(J, numV(o));
484 else if (tvisbool(o))
485 J->base[0] = TREF_PRI(t);
486 else
487 lj_trace_err(J, LJ_TRERR_BADTYPE);
488 /* Always specialize to the key. */
489 emitir(IRTG(IR_EQ, IRT_STR), J->base[1], lj_ir_kstr(J, strV(&rd->argv[1])));
490 } else {
491 /* NYI: resolving of non-function metamethods. */
492 /* NYI: non-string keys for __index table. */
493 /* NYI: stores to __newindex table. */
494 lj_trace_err(J, LJ_TRERR_BADTYPE);
495 }
496}
497
462void LJ_FASTCALL recff_cdata_index(jit_State *J, RecordFFData *rd) 498void LJ_FASTCALL recff_cdata_index(jit_State *J, RecordFFData *rd)
463{ 499{
464 TRef idx, ptr = J->base[0]; 500 TRef idx, ptr = J->base[0];
@@ -477,12 +513,13 @@ void LJ_FASTCALL recff_cdata_index(jit_State *J, RecordFFData *rd)
477 ptr = crec_reassoc_ofs(J, ptr, &ofs, 1); 513 ptr = crec_reassoc_ofs(J, ptr, &ofs, 1);
478 } 514 }
479 515
516again:
480 idx = J->base[1]; 517 idx = J->base[1];
481 if (tref_isnumber(idx)) { 518 if (tref_isnumber(idx)) {
482 idx = lj_opt_narrow_cindex(J, idx); 519 idx = lj_opt_narrow_cindex(J, idx);
483 integer_key:
484 if (ctype_ispointer(ct->info)) { 520 if (ctype_ispointer(ct->info)) {
485 CTSize sz; 521 CTSize sz;
522 integer_key:
486 if ((ct->info & CTF_COMPLEX)) 523 if ((ct->info & CTF_COMPLEX))
487 idx = emitir(IRT(IR_BAND, IRT_INTP), idx, lj_ir_kintp(J, 1)); 524 idx = emitir(IRT(IR_BAND, IRT_INTP), idx, lj_ir_kintp(J, 1));
488 sz = lj_ctype_size(cts, (sid = ctype_cid(ct->info))); 525 sz = lj_ctype_size(cts, (sid = ctype_cid(ct->info)));
@@ -495,7 +532,8 @@ void LJ_FASTCALL recff_cdata_index(jit_State *J, RecordFFData *rd)
495 CType *ctk = ctype_raw(cts, cdk->typeid); 532 CType *ctk = ctype_raw(cts, cdk->typeid);
496 IRType t; 533 IRType t;
497 if (ctype_isenum(ctk->info)) ctk = ctype_child(cts, ctk); 534 if (ctype_isenum(ctk->info)) ctk = ctype_child(cts, ctk);
498 if (ctype_isinteger(ctk->info) && (t = crec_ct2irt(ctk)) != IRT_CDATA) { 535 if (ctype_ispointer(ct->info) &&
536 ctype_isinteger(ctk->info) && (t = crec_ct2irt(ctk)) != IRT_CDATA) {
499 if (ctk->size == 8) { 537 if (ctk->size == 8) {
500 idx = emitir(IRT(IR_FLOAD, t), idx, IRFL_CDATA_INT64); 538 idx = emitir(IRT(IR_FLOAD, t), idx, IRFL_CDATA_INT64);
501 } else { 539 } else {
@@ -513,22 +551,15 @@ void LJ_FASTCALL recff_cdata_index(jit_State *J, RecordFFData *rd)
513 } 551 }
514 } else if (tref_isstr(idx)) { 552 } else if (tref_isstr(idx)) {
515 GCstr *name = strV(&rd->argv[1]); 553 GCstr *name = strV(&rd->argv[1]);
516 /* Always specialize to the field name. */
517 emitir(IRTG(IR_EQ, IRT_STR), idx, lj_ir_kstr(J, name));
518 if (cd->typeid == CTID_CTYPEID) 554 if (cd->typeid == CTID_CTYPEID)
519 ct = ctype_raw(cts, crec_constructor(J, cd, ptr)); 555 ct = ctype_raw(cts, crec_constructor(J, cd, ptr));
520 if (ctype_isptr(ct->info)) { /* Automatically perform '->'. */ 556 if (ctype_isstruct(ct->info)) {
521 CType *cct = ctype_rawchild(cts, ct);
522 if (ctype_isstruct(cct->info)) {
523 ct = cct;
524 goto index_struct;
525 }
526 } else if (ctype_isstruct(ct->info)) {
527 CTSize fofs; 557 CTSize fofs;
528 CType *fct; 558 CType *fct;
529index_struct:
530 fct = lj_ctype_getfield(cts, ct, name, &fofs); 559 fct = lj_ctype_getfield(cts, ct, name, &fofs);
531 if (fct) { 560 if (fct) {
561 /* Always specialize to the field name. */
562 emitir(IRTG(IR_EQ, IRT_STR), idx, lj_ir_kstr(J, name));
532 if (ctype_isconstval(fct->info)) { 563 if (ctype_isconstval(fct->info)) {
533 if (fct->size >= 0x80000000u && 564 if (fct->size >= 0x80000000u &&
534 (ctype_child(cts, fct)->info & CTF_UNSIGNED)) { 565 (ctype_child(cts, fct)->info & CTF_UNSIGNED)) {
@@ -546,11 +577,26 @@ index_struct:
546 ofs += (ptrdiff_t)fofs; 577 ofs += (ptrdiff_t)fofs;
547 } 578 }
548 } else if (ctype_iscomplex(ct->info)) { 579 } else if (ctype_iscomplex(ct->info)) {
549 if (strdata(name)[0] == 'i') ofs += (ct->size >> 1); 580 if (name->len == 2 &&
550 sid = ctype_cid(ct->info); 581 ((strdata(name)[0] == 'r' && strdata(name)[1] == 'e') ||
582 (strdata(name)[0] == 'i' && strdata(name)[1] == 'm'))) {
583 /* Always specialize to the field name. */
584 emitir(IRTG(IR_EQ, IRT_STR), idx, lj_ir_kstr(J, name));
585 if (strdata(name)[0] == 'i') ofs += (ct->size >> 1);
586 sid = ctype_cid(ct->info);
587 }
551 } 588 }
552 } 589 }
553 if (!sid) lj_trace_err(J, LJ_TRERR_BADTYPE); 590 if (!sid) {
591 if (ctype_isptr(ct->info)) { /* Automatically perform '->'. */
592 CType *cct = ctype_rawchild(cts, ct);
593 if (ctype_isstruct(cct->info)) {
594 ct = cct;
595 if (tref_isstr(idx)) goto again;
596 }
597 }
598 return crec_index_meta(J, cts, ct, rd);
599 }
554 600
555 if (ofs) 601 if (ofs)
556 ptr = emitir(IRT(IR_ADD, IRT_PTR), ptr, lj_ir_kintp(J, ofs)); 602 ptr = emitir(IRT(IR_ADD, IRT_PTR), ptr, lj_ir_kintp(J, ofs));
@@ -592,6 +638,7 @@ static void crec_alloc(jit_State *J, RecordFFData *rd, CTypeID id)
592 J->base[0] = emitir(IRTG(IR_CNEWI, IRT_CDATA), trid, sp); 638 J->base[0] = emitir(IRTG(IR_CNEWI, IRT_CDATA), trid, sp);
593 } else { 639 } else {
594 TRef trcd = emitir(IRTG(IR_CNEW, IRT_CDATA), trid, TREF_NIL); 640 TRef trcd = emitir(IRTG(IR_CNEW, IRT_CDATA), trid, TREF_NIL);
641 cTValue *fin;
595 J->base[0] = trcd; 642 J->base[0] = trcd;
596 if (J->base[1] && !J->base[2] && !lj_cconv_multi_init(d, &rd->argv[1])) { 643 if (J->base[1] && !J->base[2] && !lj_cconv_multi_init(d, &rd->argv[1])) {
597 goto single_init; 644 goto single_init;
@@ -660,6 +707,24 @@ static void crec_alloc(jit_State *J, RecordFFData *rd, CTypeID id)
660 crec_ct_tv(J, d, dp, lj_ir_kint(J, 0), &tv); 707 crec_ct_tv(J, d, dp, lj_ir_kint(J, 0), &tv);
661 } 708 }
662 } 709 }
710 /* Handle __gc metamethod. */
711 fin = lj_ctype_meta(cts, id, MM_gc);
712 if (fin) {
713 RecordIndex ix;
714 ix.idxchain = 0;
715 settabV(J->L, &ix.tabv, cts->finalizer);
716 ix.tab = lj_ir_ktab(J, cts->finalizer);
717 setboolV(&ix.keyv, 0); /* The key is new. Dummy value is ok here. */
718 ix.key = trcd;
719 copyTV(J->L, &ix.valv, fin);
720 if (tvisfunc(fin))
721 ix.val = lj_ir_kfunc(J, funcV(fin));
722 else if (tviscdata(fin))
723 ix.val = lj_ir_kgc(J, obj2gco(cdataV(fin)), IRT_CDATA);
724 else
725 lj_trace_err(J, LJ_TRERR_BADTYPE);
726 lj_record_idx(J, &ix);
727 }
663 } 728 }
664} 729}
665 730
@@ -849,6 +914,27 @@ static TRef crec_arith_ptr(jit_State *J, TRef *sp, CType **s, MMS mm)
849 } 914 }
850} 915}
851 916
917/* Record ctype arithmetic metamethods. */
918static void crec_arith_meta(jit_State *J, CTState *cts, RecordFFData *rd)
919{
920 cTValue *tv = NULL;
921 if (J->base[0]) {
922 if (tviscdata(&rd->argv[0]))
923 tv = lj_ctype_meta(cts, argv2cdata(J, J->base[0], &rd->argv[0])->typeid,
924 (MMS)rd->data);
925 if (!tv && J->base[1] && tviscdata(&rd->argv[1]))
926 tv = lj_ctype_meta(cts, argv2cdata(J, J->base[1], &rd->argv[1])->typeid,
927 (MMS)rd->data);
928 }
929 if (tv && tvisfunc(tv)) {
930 J->base[-1] = lj_ir_kfunc(J, funcV(tv)) | TREF_FRAME;
931 rd->nres = -1; /* Pending tailcall. */
932 } else {
933 /* NYI: non-function metamethods. */
934 lj_trace_err(J, LJ_TRERR_BADTYPE);
935 }
936}
937
852void LJ_FASTCALL recff_cdata_arith(jit_State *J, RecordFFData *rd) 938void LJ_FASTCALL recff_cdata_arith(jit_State *J, RecordFFData *rd)
853{ 939{
854 CTState *cts = ctype_ctsG(J2G(J)); 940 CTState *cts = ctype_ctsG(J2G(J));
@@ -858,7 +944,9 @@ void LJ_FASTCALL recff_cdata_arith(jit_State *J, RecordFFData *rd)
858 for (i = 0; i < 2; i++) { 944 for (i = 0; i < 2; i++) {
859 TRef tr = J->base[i]; 945 TRef tr = J->base[i];
860 CType *ct = ctype_get(cts, CTID_DOUBLE); 946 CType *ct = ctype_get(cts, CTID_DOUBLE);
861 if (tref_iscdata(tr)) { 947 if (!tr) {
948 goto trymeta;
949 } else if (tref_iscdata(tr)) {
862 CTypeID id = argv2cdata(J, tr, &rd->argv[i])->typeid; 950 CTypeID id = argv2cdata(J, tr, &rd->argv[i])->typeid;
863 ct = ctype_raw(cts, id); 951 ct = ctype_raw(cts, id);
864 if (ctype_isptr(ct->info)) { /* Resolve pointer or reference. */ 952 if (ctype_isptr(ct->info)) { /* Resolve pointer or reference. */
@@ -876,11 +964,11 @@ void LJ_FASTCALL recff_cdata_arith(jit_State *J, RecordFFData *rd)
876 if (ctype_isenum(ct->info)) ct = ctype_child(cts, ct); 964 if (ctype_isenum(ct->info)) ct = ctype_child(cts, ct);
877 if (ctype_isnum(ct->info)) { 965 if (ctype_isnum(ct->info)) {
878 IRType t = crec_ct2irt(ct); 966 IRType t = crec_ct2irt(ct);
879 if (t == IRT_CDATA) goto err_type; 967 if (t == IRT_CDATA) goto trymeta;
880 if (t == IRT_I64 || t == IRT_U64) lj_needsplit(J); 968 if (t == IRT_I64 || t == IRT_U64) lj_needsplit(J);
881 tr = emitir(IRT(IR_XLOAD, t), tr, 0); 969 tr = emitir(IRT(IR_XLOAD, t), tr, 0);
882 } else if (!(ctype_isptr(ct->info) || ctype_isrefarray(ct->info))) { 970 } else if (!(ctype_isptr(ct->info) || ctype_isrefarray(ct->info))) {
883 goto err_type; 971 goto trymeta;
884 } 972 }
885 } else if (tref_isnil(tr)) { 973 } else if (tref_isnil(tr)) {
886 tr = lj_ir_kptr(J, NULL); 974 tr = lj_ir_kptr(J, NULL);
@@ -888,7 +976,7 @@ void LJ_FASTCALL recff_cdata_arith(jit_State *J, RecordFFData *rd)
888 } else if (tref_isinteger(tr)) { 976 } else if (tref_isinteger(tr)) {
889 ct = ctype_get(cts, CTID_INT32); 977 ct = ctype_get(cts, CTID_INT32);
890 } else if (!tref_isnum(tr)) { 978 } else if (!tref_isnum(tr)) {
891 goto err_type; 979 goto trymeta;
892 } 980 }
893 ok: 981 ok:
894 s[i] = ct; 982 s[i] = ct;
@@ -896,21 +984,22 @@ void LJ_FASTCALL recff_cdata_arith(jit_State *J, RecordFFData *rd)
896 } 984 }
897 { 985 {
898 TRef tr; 986 TRef tr;
899 if (!(tr = crec_arith_int64(J, sp, s, (MMS)rd->data)) && 987 if ((tr = crec_arith_int64(J, sp, s, (MMS)rd->data)) ||
900 !(tr = crec_arith_ptr(J, sp, s, (MMS)rd->data))) { 988 (tr = crec_arith_ptr(J, sp, s, (MMS)rd->data))) {
901 err_type: 989 J->base[0] = tr;
902 lj_trace_err(J, LJ_TRERR_BADTYPE); 990 /* Fixup cdata comparisons, too. Avoids some cdata escapes. */
903 } 991 if (J->postproc == LJ_POST_FIXGUARD && frame_iscont(J->L->base-1)) {
904 /* Fixup cdata comparisons, too. Avoids some cdata escapes. */ 992 const BCIns *pc = frame_contpc(J->L->base-1) - 1;
905 if (J->postproc == LJ_POST_FIXGUARD && frame_iscont(J->L->base-1)) { 993 if (bc_op(*pc) <= BC_ISNEP) {
906 const BCIns *pc = frame_contpc(J->L->base-1) - 1; 994 setframe_pc(&J2G(J)->tmptv, pc);
907 if (bc_op(*pc) <= BC_ISNEP) { 995 J2G(J)->tmptv.u32.lo = ((tref_istrue(tr) ^ bc_op(*pc)) & 1);
908 setframe_pc(&J2G(J)->tmptv, pc); 996 J->postproc = LJ_POST_FIXCOMP;
909 J2G(J)->tmptv.u32.lo = ((tref_istrue(tr) ^ bc_op(*pc)) & 1); 997 }
910 J->postproc = LJ_POST_FIXCOMP;
911 } 998 }
999 } else {
1000 trymeta:
1001 crec_arith_meta(J, cts, rd);
912 } 1002 }
913 J->base[0] = tr;
914 } 1003 }
915} 1004}
916 1005
diff --git a/src/lj_ctype.c b/src/lj_ctype.c
index ae360b54..0b59b48d 100644
--- a/src/lj_ctype.c
+++ b/src/lj_ctype.c
@@ -306,6 +306,22 @@ CTInfo lj_ctype_info(CTState *cts, CTypeID id, CTSize *szp)
306 return qual; 306 return qual;
307} 307}
308 308
309/* Get ctype metamethod. */
310cTValue *lj_ctype_meta(CTState *cts, CTypeID id, MMS mm)
311{
312 CType *ct = ctype_get(cts, id);
313 cTValue *tv;
314 while (ctype_isattrib(ct->info)) {
315 id = ctype_cid(ct->info);
316 ct = ctype_get(cts, id);
317 }
318 tv = lj_tab_getint(cts->metatype, (int32_t)id);
319 if (tv && tvistab(tv) &&
320 (tv = lj_tab_getstr(tabV(tv), mmname_str(cts->g, mm))) && !tvisnil(tv))
321 return tv;
322 return NULL;
323}
324
309/* -- C type representation ----------------------------------------------- */ 325/* -- C type representation ----------------------------------------------- */
310 326
311/* Fixed max. length of a C type representation. */ 327/* Fixed max. length of a C type representation. */
diff --git a/src/lj_ctype.h b/src/lj_ctype.h
index a45767c2..f7a7121b 100644
--- a/src/lj_ctype.h
+++ b/src/lj_ctype.h
@@ -159,6 +159,7 @@ typedef struct CTState {
159 lua_State *L; /* Lua state (needed for errors and allocations). */ 159 lua_State *L; /* Lua state (needed for errors and allocations). */
160 global_State *g; /* Global state. */ 160 global_State *g; /* Global state. */
161 GCtab *finalizer; /* Map of cdata to finalizer. */ 161 GCtab *finalizer; /* Map of cdata to finalizer. */
162 GCtab *metatype; /* Map of CTypeID to metatable. */
162 CTypeID1 hash[CTHASH_SIZE]; /* Hash anchors for C type table. */ 163 CTypeID1 hash[CTHASH_SIZE]; /* Hash anchors for C type table. */
163} CTState; 164} CTState;
164 165
@@ -426,6 +427,7 @@ LJ_FUNC CType *lj_ctype_rawref(CTState *cts, CTypeID id);
426LJ_FUNC CTSize lj_ctype_size(CTState *cts, CTypeID id); 427LJ_FUNC CTSize lj_ctype_size(CTState *cts, CTypeID id);
427LJ_FUNC CTSize lj_ctype_vlsize(CTState *cts, CType *ct, CTSize nelem); 428LJ_FUNC CTSize lj_ctype_vlsize(CTState *cts, CType *ct, CTSize nelem);
428LJ_FUNC CTInfo lj_ctype_info(CTState *cts, CTypeID id, CTSize *szp); 429LJ_FUNC CTInfo lj_ctype_info(CTState *cts, CTypeID id, CTSize *szp);
430LJ_FUNC cTValue *lj_ctype_meta(CTState *cts, CTypeID id, MMS mm);
429LJ_FUNC GCstr *lj_ctype_repr(lua_State *L, CTypeID id, GCstr *name); 431LJ_FUNC GCstr *lj_ctype_repr(lua_State *L, CTypeID id, GCstr *name);
430LJ_FUNC GCstr *lj_ctype_repr_int64(lua_State *L, uint64_t n, int isunsigned); 432LJ_FUNC GCstr *lj_ctype_repr_int64(lua_State *L, uint64_t n, int isunsigned);
431LJ_FUNC GCstr *lj_ctype_repr_complex(lua_State *L, void *sp, CTSize size); 433LJ_FUNC GCstr *lj_ctype_repr_complex(lua_State *L, void *sp, CTSize size);