mirror of
https://github.com/LuaJIT/LuaJIT.git
synced 2025-02-07 15:14:08 +00:00
FFI: Add ctype metamethods and ffi.metatype().
This commit is contained in:
parent
fa5cd010e8
commit
3b6f37dd2c
@ -238,6 +238,31 @@ This functions is mainly useful to override the pointer compatibility
|
|||||||
checks or to convert pointers to addresses or vice versa.
|
checks or to convert pointers to addresses or vice versa.
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
|
<h3 id="ffi_metatype"><tt>ctype = ffi.metatype(ct, metatable)</tt></h3>
|
||||||
|
<p>
|
||||||
|
Creates a ctype object for the given <tt>ct</tt> and associates it with
|
||||||
|
a metatable. Only <tt>struct</tt>/<tt>union</tt> types, complex numbers
|
||||||
|
and vectors are allowed. Other types may be wrapped in a
|
||||||
|
<tt>struct</tt>, if needed.
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
The association with a metatable is permanent and cannot be changed
|
||||||
|
afterwards. Neither the contents of the <tt>metatable</tt> nor the
|
||||||
|
contents of an <tt>__index</tt> table (if any) may be modified
|
||||||
|
afterwards. The associated metatable automatically applies to all uses
|
||||||
|
of this type, no matter how the objects are created or where they
|
||||||
|
originate from. Note that pre-defined operations on types have
|
||||||
|
precedence (e.g. declared field names cannot be overriden).
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
All standard Lua metamethods are implemented. These are called directly,
|
||||||
|
without shortcuts and on any mix of types. For binary operations, the
|
||||||
|
left operand is checked first for a valid ctype metamethod. The
|
||||||
|
<tt>__gc</tt> metamethod only applies to <tt>struct</tt>/<tt>union</tt>
|
||||||
|
types and performs an implicit <a href="#ffi_gc"><tt>ffi.gc()</tt></a>
|
||||||
|
call during creation of an instance.
|
||||||
|
</p>
|
||||||
|
|
||||||
<h3 id="ffi_gc"><tt>cdata = ffi.gc(cdata, finalizer)</tt></h3>
|
<h3 id="ffi_gc"><tt>cdata = ffi.gc(cdata, finalizer)</tt></h3>
|
||||||
<p>
|
<p>
|
||||||
Associates a finalizer with a pointer or aggregate cdata object. The
|
Associates a finalizer with a pointer or aggregate cdata object. The
|
||||||
|
@ -582,6 +582,10 @@ Reference types are dereferenced <em>before</em> performing each of
|
|||||||
the operations below — the operation is applied to the
|
the operations below — the operation is applied to the
|
||||||
C type pointed to by the reference.
|
C type pointed to by the reference.
|
||||||
</p>
|
</p>
|
||||||
|
<p>
|
||||||
|
The pre-defined operations are always tried first before deferring to a
|
||||||
|
metamethod for a ctype (if defined).
|
||||||
|
</p>
|
||||||
|
|
||||||
<h3 id="cdata_array">Indexing a cdata object</h3>
|
<h3 id="cdata_array">Indexing a cdata object</h3>
|
||||||
<ul>
|
<ul>
|
||||||
@ -803,9 +807,10 @@ vararg functions</a>.
|
|||||||
</p>
|
</p>
|
||||||
<p>
|
<p>
|
||||||
Memory areas returned by C functions (e.g. from <tt>malloc()</tt>)
|
Memory areas returned by C functions (e.g. from <tt>malloc()</tt>)
|
||||||
must be manually managed, of course. Pointers to cdata objects are
|
must be manually managed, of course (or use
|
||||||
indistinguishable from pointers returned by C functions (which is one
|
<a href="ext_ffi_api.html#ffi_gc"><tt>ffi.gc()</tt></a>)). Pointers to
|
||||||
of the reasons why the GC cannot follow them).
|
cdata objects are indistinguishable from pointers returned by C
|
||||||
|
functions (which is one of the reasons why the GC cannot follow them).
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<h2 id="clib">C Library Namespaces</h2>
|
<h2 id="clib">C Library Namespaces</h2>
|
||||||
@ -977,6 +982,9 @@ two.</li>
|
|||||||
value.</li>
|
value.</li>
|
||||||
<li>Calls to C functions with 64 bit arguments or return values
|
<li>Calls to C functions with 64 bit arguments or return values
|
||||||
on 32 bit CPUs.</li>
|
on 32 bit CPUs.</li>
|
||||||
|
<li>Calls to ctype metamethods which are not plain functions.</li>
|
||||||
|
<li>ctype <tt>__newindex</tt> tables and non-string lookups in ctype
|
||||||
|
<tt>__index</tt> tables.</li>
|
||||||
<li>Accesses to external variables in C library namespaces.</li>
|
<li>Accesses to external variables in C library namespaces.</li>
|
||||||
<li><tt>tostring()</tt> for cdata types.</li>
|
<li><tt>tostring()</tt> for cdata types.</li>
|
||||||
<li>The following <a href="ext_ffi_api.html">ffi.* API</a> functions:
|
<li>The following <a href="ext_ffi_api.html">ffi.* API</a> functions:
|
||||||
@ -988,7 +996,6 @@ Other missing features:
|
|||||||
<ul>
|
<ul>
|
||||||
<li>Bit operations for 64 bit types.</li>
|
<li>Bit operations for 64 bit types.</li>
|
||||||
<li>Arithmetic for <tt>complex</tt> numbers.</li>
|
<li>Arithmetic for <tt>complex</tt> numbers.</li>
|
||||||
<li>User-defined metamethods for C types.</li>
|
|
||||||
<li>Callbacks from C code to Lua functions.</li>
|
<li>Callbacks from C code to Lua functions.</li>
|
||||||
<li>Atomic handling of <tt>errno</tt>.</li>
|
<li>Atomic handling of <tt>errno</tt>.</li>
|
||||||
<li>Passing structs by value to vararg C functions.</li>
|
<li>Passing structs by value to vararg C functions.</li>
|
||||||
|
@ -386,6 +386,99 @@ application might work on some systems, but would fail in a POSIX/x64
|
|||||||
environment.
|
environment.
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
|
<h2 id="metatype">Defining Metamethods for a C Type</h2>
|
||||||
|
<p>
|
||||||
|
The following code explains how to define metamethods for a C type.
|
||||||
|
We define a simple point type and add some operations to it:
|
||||||
|
</p>
|
||||||
|
<pre class="code mark">
|
||||||
|
<span class="codemark">
|
||||||
|
①
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
②
|
||||||
|
|
||||||
|
③
|
||||||
|
|
||||||
|
④
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
⑤
|
||||||
|
|
||||||
|
⑥</span>local ffi = require("ffi")
|
||||||
|
ffi.cdef[[
|
||||||
|
<span style="color:#00a000;">typedef struct { double x, y; } point_t;</span>
|
||||||
|
]]
|
||||||
|
|
||||||
|
local point
|
||||||
|
local mt = {
|
||||||
|
__add = function(a, b) return point(a.x+b.x, a.y+b.y) end,
|
||||||
|
__len = function(a) return math.sqrt(a.x*a.x + a.y*a.y) end,
|
||||||
|
__index = {
|
||||||
|
area = function(a) return a.x*a.x + a.y*a.y end,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
point = ffi.metatype("point_t", mt)
|
||||||
|
|
||||||
|
local a = point(3, 4)
|
||||||
|
print(a.x, a.y) --> 3 4
|
||||||
|
print(#a) --> 5
|
||||||
|
print(a:area()) --> 25
|
||||||
|
local b = a + point(0.5, 8)
|
||||||
|
print(#b) --> 12.5
|
||||||
|
</pre>
|
||||||
|
<p>
|
||||||
|
Here's the step-by-step explanation:
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
<span class="mark">①</span> This defines the C type for a
|
||||||
|
two-dimensional point object.
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
<span class="mark">②</span> We have to declare the variable
|
||||||
|
holding the point constructor first, because it's used inside of a
|
||||||
|
metamethod.
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
<span class="mark">③</span> Let's define an <tt>__add</tt>
|
||||||
|
metamethod which adds the coordinates of two points and creates a new
|
||||||
|
point object. For simplicity, this function assumes that both arguments
|
||||||
|
are points. But it could be any mix of objects, if at least one operand
|
||||||
|
is of the required type (e.g. adding a point plus a number or vice
|
||||||
|
versa). Our <tt>__len</tt> metamethod returns the distance of a point to
|
||||||
|
the origin.
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
<span class="mark">④</span> If we run out of operators, we can
|
||||||
|
define named methods, too. Here the <tt>__index</tt> table defines an
|
||||||
|
<tt>area</tt> function. For custom indexing needs, one might want to
|
||||||
|
define <tt>__index</tt> and <tt>__newindex</tt> functions instead.
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
<span class="mark">⑤</span> This associates the metamethods with
|
||||||
|
our C type. This only needs to be done once. For convenience, a
|
||||||
|
constructor is returned by
|
||||||
|
<a href="ffi_ext_api.html#ffi_metatype"><tt>ffi.metatype()</tt></a>.
|
||||||
|
We're not required to use it, though. The original C type can still
|
||||||
|
be used e.g. to create an array of points. The metamethods automatically
|
||||||
|
apply to any and all uses of this type.
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
Please note that the association with a metatable is permanent and
|
||||||
|
<b>the metatable must not be modified afterwards!</b> Ditto for the
|
||||||
|
<tt>__index</tt> table.
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
<span class="mark">⑥</span> Here are some simple usage examples
|
||||||
|
for the point type and their expected results. The pre-defined
|
||||||
|
operations (such as <tt>a.x</tt>) can be freely mixed with the newly
|
||||||
|
defined metamethods. Note that <tt>area</tt> is a method and must be
|
||||||
|
called with the Lua syntax for methods: <tt>a:area()</tt>, not
|
||||||
|
<tt>a.area()</tt>.
|
||||||
|
</p>
|
||||||
|
|
||||||
<h2 id="idioms">Translating C Idioms</h2>
|
<h2 id="idioms">Translating C Idioms</h2>
|
||||||
<p>
|
<p>
|
||||||
Here's a list of common C idioms and their translation to the
|
Here's a list of common C idioms and their translation to the
|
||||||
|
@ -21,9 +21,9 @@ lib_bit.o: lib_bit.c lua.h luaconf.h lauxlib.h lualib.h lj_obj.h lj_def.h \
|
|||||||
lib_debug.o: lib_debug.c lua.h luaconf.h lauxlib.h lualib.h lj_obj.h \
|
lib_debug.o: lib_debug.c lua.h luaconf.h lauxlib.h lualib.h lj_obj.h \
|
||||||
lj_def.h lj_arch.h lj_err.h lj_errmsg.h lj_lib.h lj_libdef.h
|
lj_def.h lj_arch.h lj_err.h lj_errmsg.h lj_lib.h lj_libdef.h
|
||||||
lib_ffi.o: lib_ffi.c lua.h luaconf.h lauxlib.h lualib.h lj_obj.h lj_def.h \
|
lib_ffi.o: lib_ffi.c lua.h luaconf.h lauxlib.h lualib.h lj_obj.h lj_def.h \
|
||||||
lj_arch.h lj_gc.h lj_err.h lj_errmsg.h lj_str.h lj_tab.h lj_ctype.h \
|
lj_arch.h lj_gc.h lj_err.h lj_errmsg.h lj_str.h lj_tab.h lj_meta.h \
|
||||||
lj_cparse.h lj_cdata.h lj_cconv.h lj_carith.h lj_ccall.h lj_clib.h \
|
lj_ctype.h lj_cparse.h lj_cdata.h lj_cconv.h lj_carith.h lj_ccall.h \
|
||||||
lj_ff.h lj_ffdef.h lj_lib.h lj_libdef.h
|
lj_clib.h lj_ff.h lj_ffdef.h lj_lib.h lj_libdef.h
|
||||||
lib_init.o: lib_init.c lua.h luaconf.h lauxlib.h lualib.h lj_arch.h
|
lib_init.o: lib_init.c lua.h luaconf.h lauxlib.h lualib.h lj_arch.h
|
||||||
lib_io.o: lib_io.c lua.h luaconf.h lauxlib.h lualib.h lj_obj.h lj_def.h \
|
lib_io.o: lib_io.c lua.h luaconf.h lauxlib.h lualib.h lj_obj.h lj_def.h \
|
||||||
lj_arch.h lj_gc.h lj_err.h lj_errmsg.h lj_str.h lj_ff.h lj_ffdef.h \
|
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 \
|
|||||||
lj_bc.o: lj_bc.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.h lj_bc.h \
|
lj_bc.o: lj_bc.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.h lj_bc.h \
|
||||||
lj_bcdef.h
|
lj_bcdef.h
|
||||||
lj_carith.o: lj_carith.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.h \
|
lj_carith.o: lj_carith.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.h \
|
||||||
lj_gc.h lj_err.h lj_errmsg.h lj_ctype.h lj_cconv.h lj_cdata.h \
|
lj_gc.h lj_err.h lj_errmsg.h lj_tab.h lj_meta.h lj_ctype.h lj_cconv.h \
|
||||||
lj_carith.h
|
lj_cdata.h lj_carith.h
|
||||||
lj_ccall.o: lj_ccall.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.h \
|
lj_ccall.o: lj_ccall.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.h \
|
||||||
lj_gc.h lj_err.h lj_errmsg.h lj_str.h lj_ctype.h lj_cconv.h lj_cdata.h \
|
lj_gc.h lj_err.h lj_errmsg.h lj_str.h lj_ctype.h lj_cconv.h lj_cdata.h \
|
||||||
lj_ccall.h lj_trace.h lj_jit.h lj_ir.h lj_dispatch.h lj_bc.h \
|
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 \
|
|||||||
lj_crecord.o: lj_crecord.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.h \
|
lj_crecord.o: lj_crecord.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.h \
|
||||||
lj_err.h lj_errmsg.h lj_str.h lj_tab.h lj_frame.h lj_bc.h lj_ctype.h \
|
lj_err.h lj_errmsg.h lj_str.h lj_tab.h lj_frame.h lj_bc.h lj_ctype.h \
|
||||||
lj_gc.h lj_cparse.h lj_cconv.h lj_clib.h lj_ir.h lj_jit.h lj_iropt.h \
|
lj_gc.h lj_cparse.h lj_cconv.h lj_clib.h lj_ir.h lj_jit.h lj_iropt.h \
|
||||||
lj_trace.h lj_dispatch.h lj_traceerr.h lj_ffrecord.h lj_crecord.h
|
lj_trace.h lj_dispatch.h lj_traceerr.h lj_record.h lj_ffrecord.h \
|
||||||
|
lj_crecord.h
|
||||||
lj_ctype.o: lj_ctype.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.h \
|
lj_ctype.o: lj_ctype.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.h \
|
||||||
lj_gc.h lj_err.h lj_errmsg.h lj_str.h lj_tab.h lj_ctype.h
|
lj_gc.h lj_err.h lj_errmsg.h lj_str.h lj_tab.h lj_ctype.h
|
||||||
lj_dispatch.o: lj_dispatch.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.h \
|
lj_dispatch.o: lj_dispatch.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.h \
|
||||||
|
116
src/lib_ffi.c
116
src/lib_ffi.c
@ -18,6 +18,7 @@
|
|||||||
#include "lj_err.h"
|
#include "lj_err.h"
|
||||||
#include "lj_str.h"
|
#include "lj_str.h"
|
||||||
#include "lj_tab.h"
|
#include "lj_tab.h"
|
||||||
|
#include "lj_meta.h"
|
||||||
#include "lj_ctype.h"
|
#include "lj_ctype.h"
|
||||||
#include "lj_cparse.h"
|
#include "lj_cparse.h"
|
||||||
#include "lj_cdata.h"
|
#include "lj_cdata.h"
|
||||||
@ -96,6 +97,41 @@ static int32_t ffi_checkint(lua_State *L, int narg)
|
|||||||
|
|
||||||
#define LJLIB_MODULE_ffi_meta
|
#define LJLIB_MODULE_ffi_meta
|
||||||
|
|
||||||
|
/* Handle ctype __index/__newindex metamethods. */
|
||||||
|
static int ffi_index_meta(lua_State *L, CTState *cts, CType *ct, MMS mm)
|
||||||
|
{
|
||||||
|
CTypeID id = ctype_typeid(cts, ct);
|
||||||
|
cTValue *tv = lj_ctype_meta(cts, id, mm);
|
||||||
|
TValue *base = L->base;
|
||||||
|
if (!tv) {
|
||||||
|
const char *s;
|
||||||
|
err_index:
|
||||||
|
s = strdata(lj_ctype_repr(L, id, NULL));
|
||||||
|
if (tvisstr(L->base+1))
|
||||||
|
lj_err_callerv(L, LJ_ERR_FFI_BADMEMBER, s, strVdata(L->base+1));
|
||||||
|
else
|
||||||
|
lj_err_callerv(L, LJ_ERR_FFI_BADIDX, s);
|
||||||
|
}
|
||||||
|
if (!tvisfunc(tv)) {
|
||||||
|
if (mm == MM_index) {
|
||||||
|
cTValue *o = lj_meta_tget(L, tv, base+1);
|
||||||
|
if (o) {
|
||||||
|
if (tvisnil(o)) goto err_index;
|
||||||
|
copyTV(L, L->top-1, o);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
TValue *o = lj_meta_tset(L, tv, base+1);
|
||||||
|
if (o) {
|
||||||
|
copyTV(L, o, base+2);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
tv = L->top-1;
|
||||||
|
}
|
||||||
|
return lj_meta_tailcall(L, tv);
|
||||||
|
}
|
||||||
|
|
||||||
LJLIB_CF(ffi_meta___index) LJLIB_REC(cdata_index 0)
|
LJLIB_CF(ffi_meta___index) LJLIB_REC(cdata_index 0)
|
||||||
{
|
{
|
||||||
CTState *cts = ctype_cts(L);
|
CTState *cts = ctype_cts(L);
|
||||||
@ -106,6 +142,8 @@ LJLIB_CF(ffi_meta___index) LJLIB_REC(cdata_index 0)
|
|||||||
if (!(o+1 < L->top && tviscdata(o))) /* Also checks for presence of key. */
|
if (!(o+1 < L->top && tviscdata(o))) /* Also checks for presence of key. */
|
||||||
lj_err_argt(L, 1, LUA_TCDATA);
|
lj_err_argt(L, 1, LUA_TCDATA);
|
||||||
ct = lj_cdata_index(cts, cdataV(o), o+1, &p, &qual);
|
ct = lj_cdata_index(cts, cdataV(o), o+1, &p, &qual);
|
||||||
|
if ((qual & 1))
|
||||||
|
return ffi_index_meta(L, cts, ct, MM_index);
|
||||||
if (lj_cdata_get(cts, ct, L->top-1, p))
|
if (lj_cdata_get(cts, ct, L->top-1, p))
|
||||||
lj_gc_check(L);
|
lj_gc_check(L);
|
||||||
return 1;
|
return 1;
|
||||||
@ -121,6 +159,11 @@ LJLIB_CF(ffi_meta___newindex) LJLIB_REC(cdata_index 1)
|
|||||||
if (!(o+2 < L->top && tviscdata(o))) /* Also checks for key and value. */
|
if (!(o+2 < L->top && tviscdata(o))) /* Also checks for key and value. */
|
||||||
lj_err_argt(L, 1, LUA_TCDATA);
|
lj_err_argt(L, 1, LUA_TCDATA);
|
||||||
ct = lj_cdata_index(cts, cdataV(o), o+1, &p, &qual);
|
ct = lj_cdata_index(cts, cdataV(o), o+1, &p, &qual);
|
||||||
|
if ((qual & 1)) {
|
||||||
|
if ((qual & CTF_CONST))
|
||||||
|
lj_err_caller(L, LJ_ERR_FFI_WRCONST);
|
||||||
|
return ffi_index_meta(L, cts, ct, MM_newindex);
|
||||||
|
}
|
||||||
lj_cdata_set(cts, ct, p, o+2, qual);
|
lj_cdata_set(cts, ct, p, o+2, qual);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -138,7 +181,7 @@ LJLIB_CF(ffi_meta___eq) LJLIB_REC(cdata_arith MM_eq)
|
|||||||
return ffi_arith(L);
|
return ffi_arith(L);
|
||||||
}
|
}
|
||||||
|
|
||||||
LJLIB_CF(ffi_meta___len)
|
LJLIB_CF(ffi_meta___len) LJLIB_REC(cdata_arith MM_len)
|
||||||
{
|
{
|
||||||
return ffi_arith(L);
|
return ffi_arith(L);
|
||||||
}
|
}
|
||||||
@ -153,11 +196,21 @@ LJLIB_CF(ffi_meta___le) LJLIB_REC(cdata_arith MM_le)
|
|||||||
return ffi_arith(L);
|
return ffi_arith(L);
|
||||||
}
|
}
|
||||||
|
|
||||||
LJLIB_CF(ffi_meta___concat)
|
LJLIB_CF(ffi_meta___concat) LJLIB_REC(cdata_arith MM_concat)
|
||||||
{
|
{
|
||||||
return ffi_arith(L);
|
return ffi_arith(L);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Handle ctype __call metamethod. */
|
||||||
|
static int ffi_call_meta(lua_State *L, CTypeID id)
|
||||||
|
{
|
||||||
|
CTState *cts = ctype_cts(L);
|
||||||
|
cTValue *tv = lj_ctype_meta(cts, id, MM_call);
|
||||||
|
if (!tv)
|
||||||
|
lj_err_callerv(L, LJ_ERR_FFI_BADCALL, strdata(lj_ctype_repr(L, id, NULL)));
|
||||||
|
return lj_meta_tailcall(L, tv);
|
||||||
|
}
|
||||||
|
|
||||||
/* Forward declaration. */
|
/* Forward declaration. */
|
||||||
static int lj_cf_ffi_new(lua_State *L);
|
static int lj_cf_ffi_new(lua_State *L);
|
||||||
|
|
||||||
@ -168,8 +221,7 @@ LJLIB_CF(ffi_meta___call) LJLIB_REC(cdata_call)
|
|||||||
if (cd->typeid == CTID_CTYPEID)
|
if (cd->typeid == CTID_CTYPEID)
|
||||||
return lj_cf_ffi_new(L);
|
return lj_cf_ffi_new(L);
|
||||||
if ((ret = lj_ccall_func(L, cd)) < 0)
|
if ((ret = lj_ccall_func(L, cd)) < 0)
|
||||||
lj_err_callerv(L, LJ_ERR_FFI_BADCALL,
|
return ffi_call_meta(L, cd->typeid);
|
||||||
strdata(lj_ctype_repr(L, cd->typeid, NULL)));
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -226,6 +278,12 @@ LJLIB_CF(ffi_meta___tostring)
|
|||||||
setstrV(L, L->top-1, lj_ctype_repr_int64(L, *(uint64_t *)cdataptr(cd),
|
setstrV(L, L->top-1, lj_ctype_repr_int64(L, *(uint64_t *)cdataptr(cd),
|
||||||
(ct->info & CTF_UNSIGNED)));
|
(ct->info & CTF_UNSIGNED)));
|
||||||
goto checkgc;
|
goto checkgc;
|
||||||
|
} else if (ctype_isstruct(ct->info) || ctype_isvector(ct->info)) {
|
||||||
|
/* Handle ctype __tostring metamethod. */
|
||||||
|
CTState *cts = ctype_cts(L);
|
||||||
|
cTValue *tv = lj_ctype_meta(cts, id, MM_tostring);
|
||||||
|
if (tv)
|
||||||
|
return lj_meta_tailcall(L, tv);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
lj_str_pushf(L, msg, strdata(lj_ctype_repr(L, id, NULL)), cdataptr(cd));
|
lj_str_pushf(L, msg, strdata(lj_ctype_repr(L, id, NULL)), cdataptr(cd));
|
||||||
@ -234,6 +292,8 @@ checkgc:
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
LJLIB_PUSH("ffi") LJLIB_SET(__metatable)
|
||||||
|
|
||||||
#include "lj_libdef.h"
|
#include "lj_libdef.h"
|
||||||
|
|
||||||
/* -- C library metamethods ----------------------------------------------- */
|
/* -- C library metamethods ----------------------------------------------- */
|
||||||
@ -331,14 +391,14 @@ LJLIB_CF(ffi_new) LJLIB_REC(.)
|
|||||||
{
|
{
|
||||||
CTState *cts = ctype_cts(L);
|
CTState *cts = ctype_cts(L);
|
||||||
CTypeID id = ffi_checkctype(L, cts);
|
CTypeID id = ffi_checkctype(L, cts);
|
||||||
|
CType *ct = ctype_raw(cts, id);
|
||||||
CTSize sz;
|
CTSize sz;
|
||||||
CTInfo info = lj_ctype_info(cts, id, &sz);
|
CTInfo info = lj_ctype_info(cts, id, &sz);
|
||||||
TValue *o = L->base+1;
|
TValue *o = L->base+1;
|
||||||
GCcdata *cd;
|
GCcdata *cd;
|
||||||
if ((info & CTF_VLA)) {
|
if ((info & CTF_VLA)) {
|
||||||
o++;
|
o++;
|
||||||
sz = lj_ctype_vlsize(cts, ctype_raw(cts, id),
|
sz = lj_ctype_vlsize(cts, ct, (CTSize)ffi_checkint(L, 2));
|
||||||
(CTSize)ffi_checkint(L, 2));
|
|
||||||
}
|
}
|
||||||
if (sz == CTSIZE_INVALID)
|
if (sz == CTSIZE_INVALID)
|
||||||
lj_err_arg(L, 1, LJ_ERR_FFI_INVSIZE);
|
lj_err_arg(L, 1, LJ_ERR_FFI_INVSIZE);
|
||||||
@ -347,8 +407,21 @@ LJLIB_CF(ffi_new) LJLIB_REC(.)
|
|||||||
else
|
else
|
||||||
cd = lj_cdata_newv(cts, id, sz, ctype_align(info));
|
cd = lj_cdata_newv(cts, id, sz, ctype_align(info));
|
||||||
setcdataV(L, o-1, cd); /* Anchor the uninitialized cdata. */
|
setcdataV(L, o-1, cd); /* Anchor the uninitialized cdata. */
|
||||||
lj_cconv_ct_init(cts, ctype_raw(cts, id), sz, cdataptr(cd),
|
lj_cconv_ct_init(cts, ct, sz, cdataptr(cd),
|
||||||
o, (MSize)(L->top - o)); /* Initialize cdata. */
|
o, (MSize)(L->top - o)); /* Initialize cdata. */
|
||||||
|
if (ctype_isstruct(ct->info)) {
|
||||||
|
/* Handle ctype __gc metamethod. Use the fast lookup here. */
|
||||||
|
cTValue *tv = lj_tab_getint(cts->metatype, (int32_t)id);
|
||||||
|
if (tv && tvistab(tv) && (tv = lj_meta_fast(L, tabV(tv), MM_gc))) {
|
||||||
|
GCtab *t = cts->finalizer;
|
||||||
|
if (gcref(t->metatable)) {
|
||||||
|
/* Add to finalizer table, if still enabled. */
|
||||||
|
copyTV(L, lj_tab_set(L, t, o-1), tv);
|
||||||
|
lj_gc_anybarriert(L, t);
|
||||||
|
cd->marked |= LJ_GC_CDATA_FIN;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
L->top = o; /* Only return the cdata itself. */
|
L->top = o; /* Only return the cdata itself. */
|
||||||
lj_gc_check(L);
|
lj_gc_check(L);
|
||||||
return 1;
|
return 1;
|
||||||
@ -521,7 +594,33 @@ LJLIB_CF(ffi_abi) LJLIB_REC(.)
|
|||||||
|
|
||||||
#undef H_
|
#undef H_
|
||||||
|
|
||||||
LJLIB_PUSH(top-7) LJLIB_SET(!) /* Store reference to weak table. */
|
LJLIB_PUSH(top-8) LJLIB_SET(!) /* Store reference to metatype table. */
|
||||||
|
|
||||||
|
LJLIB_CF(ffi_metatype)
|
||||||
|
{
|
||||||
|
CTState *cts = ctype_cts(L);
|
||||||
|
CTypeID id = ffi_checkctype(L, cts);
|
||||||
|
GCtab *mt = lj_lib_checktab(L, 2);
|
||||||
|
GCtab *t = cts->metatype;
|
||||||
|
CType *ct = ctype_get(cts, id); /* Only allow raw types. */
|
||||||
|
TValue *tv;
|
||||||
|
GCcdata *cd;
|
||||||
|
if (!(ctype_isstruct(ct->info) || ctype_iscomplex(ct->info) ||
|
||||||
|
ctype_isvector(ct->info)))
|
||||||
|
lj_err_arg(L, 1, LJ_ERR_FFI_INVTYPE);
|
||||||
|
tv = lj_tab_setint(L, t, (int32_t)id);
|
||||||
|
if (!tvisnil(tv))
|
||||||
|
lj_err_caller(L, LJ_ERR_PROTMT);
|
||||||
|
settabV(L, tv, mt);
|
||||||
|
lj_gc_anybarriert(L, t);
|
||||||
|
cd = lj_cdata_new(cts, CTID_CTYPEID, 4);
|
||||||
|
*(CTypeID *)cdataptr(cd) = id;
|
||||||
|
setcdataV(L, L->top-1, cd);
|
||||||
|
lj_gc_check(L);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
LJLIB_PUSH(top-7) LJLIB_SET(!) /* Store reference to finalizer table. */
|
||||||
|
|
||||||
LJLIB_CF(ffi_gc)
|
LJLIB_CF(ffi_gc)
|
||||||
{
|
{
|
||||||
@ -590,6 +689,7 @@ static void ffi_register_module(lua_State *L)
|
|||||||
LUALIB_API int luaopen_ffi(lua_State *L)
|
LUALIB_API int luaopen_ffi(lua_State *L)
|
||||||
{
|
{
|
||||||
CTState *cts = lj_ctype_init(L);
|
CTState *cts = lj_ctype_init(L);
|
||||||
|
settabV(L, L->top++, (cts->metatype = lj_tab_new(L, 0, 0)));
|
||||||
cts->finalizer = ffi_finalizer(L);
|
cts->finalizer = ffi_finalizer(L);
|
||||||
LJ_LIB_REG(L, NULL, ffi_meta);
|
LJ_LIB_REG(L, NULL, ffi_meta);
|
||||||
/* NOBARRIER: basemt is a GC root. */
|
/* NOBARRIER: basemt is a GC root. */
|
||||||
|
@ -2558,6 +2558,7 @@ static void asm_cnew(ASMState *as, IRIns *ir)
|
|||||||
lj_ctype_size(cts, typeid) : (CTSize)IR(ir->op2)->i;
|
lj_ctype_size(cts, typeid) : (CTSize)IR(ir->op2)->i;
|
||||||
const CCallInfo *ci = &lj_ir_callinfo[IRCALL_lj_mem_newgco];
|
const CCallInfo *ci = &lj_ir_callinfo[IRCALL_lj_mem_newgco];
|
||||||
IRRef args[2];
|
IRRef args[2];
|
||||||
|
int gcfin = 0;
|
||||||
lua_assert(sz != CTSIZE_INVALID);
|
lua_assert(sz != CTSIZE_INVALID);
|
||||||
|
|
||||||
args[0] = ASMREF_L; /* lua_State *L */
|
args[0] = ASMREF_L; /* lua_State *L */
|
||||||
@ -2604,12 +2605,15 @@ static void asm_cnew(ASMState *as, IRIns *ir)
|
|||||||
} while (1);
|
} while (1);
|
||||||
#endif
|
#endif
|
||||||
lua_assert(sz == 4 || (sz == 8 && (LJ_64 || LJ_HASFFI)));
|
lua_assert(sz == 4 || (sz == 8 && (LJ_64 || LJ_HASFFI)));
|
||||||
|
} else {
|
||||||
|
if (lj_ctype_meta(cts, typeid, MM_gc) != NULL)
|
||||||
|
gcfin = LJ_GC_CDATA_FIN;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Combine initialization of marked, gct and typeid. */
|
/* Combine initialization of marked, gct and typeid. */
|
||||||
emit_movtomro(as, RID_ECX, RID_RET, offsetof(GCcdata, marked));
|
emit_movtomro(as, RID_ECX, RID_RET, offsetof(GCcdata, marked));
|
||||||
emit_gri(as, XG_ARITHi(XOg_OR), RID_ECX,
|
emit_gri(as, XG_ARITHi(XOg_OR), RID_ECX,
|
||||||
(int32_t)((~LJ_TCDATA<<8)+(typeid<<16)));
|
(int32_t)((~LJ_TCDATA<<8)+(typeid<<16)+gcfin));
|
||||||
emit_gri(as, XG_ARITHi(XOg_AND), RID_ECX, LJ_GC_WHITES);
|
emit_gri(as, XG_ARITHi(XOg_AND), RID_ECX, LJ_GC_WHITES);
|
||||||
emit_opgl(as, XO_MOVZXb, RID_ECX, gc.currentwhite);
|
emit_opgl(as, XO_MOVZXb, RID_ECX, gc.currentwhite);
|
||||||
|
|
||||||
|
@ -9,6 +9,8 @@
|
|||||||
|
|
||||||
#include "lj_gc.h"
|
#include "lj_gc.h"
|
||||||
#include "lj_err.h"
|
#include "lj_err.h"
|
||||||
|
#include "lj_tab.h"
|
||||||
|
#include "lj_meta.h"
|
||||||
#include "lj_ctype.h"
|
#include "lj_ctype.h"
|
||||||
#include "lj_cconv.h"
|
#include "lj_cconv.h"
|
||||||
#include "lj_cdata.h"
|
#include "lj_cdata.h"
|
||||||
@ -187,6 +189,31 @@ static int carith_int64(lua_State *L, CTState *cts, CDArith *ca, MMS mm)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Handle ctype arithmetic metamethods. */
|
||||||
|
static int lj_carith_meta(lua_State *L, CTState *cts, CDArith *ca, MMS mm)
|
||||||
|
{
|
||||||
|
cTValue *tv = NULL;
|
||||||
|
if (tviscdata(L->base))
|
||||||
|
tv = lj_ctype_meta(cts, cdataV(L->base)->typeid, mm);
|
||||||
|
if (!tv && L->base+1 < L->top && tviscdata(L->base+1))
|
||||||
|
tv = lj_ctype_meta(cts, cdataV(L->base+1)->typeid, mm);
|
||||||
|
if (!tv) {
|
||||||
|
const char *repr[2];
|
||||||
|
int i;
|
||||||
|
for (i = 0; i < 2; i++) {
|
||||||
|
if (ca->ct[i])
|
||||||
|
repr[i] = strdata(lj_ctype_repr(L, ctype_typeid(cts, ca->ct[i]), NULL));
|
||||||
|
else
|
||||||
|
repr[i] = typename(&L->base[i]);
|
||||||
|
}
|
||||||
|
lj_err_callerv(L, mm == MM_len ? LJ_ERR_FFI_BADLEN :
|
||||||
|
mm == MM_concat ? LJ_ERR_FFI_BADCONCAT :
|
||||||
|
mm < MM_add ? LJ_ERR_FFI_BADCOMP : LJ_ERR_FFI_BADARITH,
|
||||||
|
repr[0], repr[1]);
|
||||||
|
}
|
||||||
|
return lj_meta_tailcall(L, tv);
|
||||||
|
}
|
||||||
|
|
||||||
/* Arithmetic operators for cdata. */
|
/* Arithmetic operators for cdata. */
|
||||||
int lj_carith_op(lua_State *L, MMS mm)
|
int lj_carith_op(lua_State *L, MMS mm)
|
||||||
{
|
{
|
||||||
@ -198,22 +225,7 @@ int lj_carith_op(lua_State *L, MMS mm)
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/* NYI: per-cdata metamethods. */
|
return lj_carith_meta(L, cts, &ca, mm);
|
||||||
{
|
|
||||||
const char *repr[2];
|
|
||||||
int i;
|
|
||||||
for (i = 0; i < 2; i++) {
|
|
||||||
if (ca.ct[i])
|
|
||||||
repr[i] = strdata(lj_ctype_repr(L, ctype_typeid(cts, ca.ct[i]), NULL));
|
|
||||||
else
|
|
||||||
repr[i] = typename(&L->base[i]);
|
|
||||||
}
|
|
||||||
lj_err_callerv(L, mm == MM_len ? LJ_ERR_FFI_BADLEN :
|
|
||||||
mm == MM_concat ? LJ_ERR_FFI_BADCONCAT :
|
|
||||||
mm < MM_add ? LJ_ERR_FFI_BADCOMP : LJ_ERR_FFI_BADARITH,
|
|
||||||
repr[0], repr[1]);
|
|
||||||
}
|
|
||||||
return 0; /* unreachable */
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* -- 64 bit integer arithmetic helpers ----------------------------------- */
|
/* -- 64 bit integer arithmetic helpers ----------------------------------- */
|
||||||
|
@ -129,13 +129,7 @@ collect_attrib:
|
|||||||
}
|
}
|
||||||
} else if (tvisstr(key)) { /* String key. */
|
} else if (tvisstr(key)) { /* String key. */
|
||||||
GCstr *name = strV(key);
|
GCstr *name = strV(key);
|
||||||
if (ctype_isptr(ct->info)) { /* Automatically perform '->'. */
|
if (ctype_isstruct(ct->info)) {
|
||||||
if (ctype_isstruct(ctype_rawchild(cts, ct)->info)) {
|
|
||||||
p = (uint8_t *)cdata_getptr(p, ct->size);
|
|
||||||
ct = ctype_child(cts, ct);
|
|
||||||
goto collect_attrib;
|
|
||||||
}
|
|
||||||
} if (ctype_isstruct(ct->info)) {
|
|
||||||
CTSize ofs;
|
CTSize ofs;
|
||||||
CType *fct = lj_ctype_getfield(cts, ct, name, &ofs);
|
CType *fct = lj_ctype_getfield(cts, ct, name, &ofs);
|
||||||
if (fct) {
|
if (fct) {
|
||||||
@ -155,7 +149,7 @@ collect_attrib:
|
|||||||
}
|
}
|
||||||
} else if (cd->typeid == CTID_CTYPEID) {
|
} else if (cd->typeid == CTID_CTYPEID) {
|
||||||
/* Allow indexing a (pointer to) struct constructor to get constants. */
|
/* Allow indexing a (pointer to) struct constructor to get constants. */
|
||||||
CType *sct = ct = ctype_raw(cts, *(CTypeID *)p);
|
CType *sct = ctype_raw(cts, *(CTypeID *)p);
|
||||||
if (ctype_isptr(sct->info))
|
if (ctype_isptr(sct->info))
|
||||||
sct = ctype_rawchild(cts, sct);
|
sct = ctype_rawchild(cts, sct);
|
||||||
if (ctype_isstruct(sct->info)) {
|
if (ctype_isstruct(sct->info)) {
|
||||||
@ -165,16 +159,16 @@ collect_attrib:
|
|||||||
return fct;
|
return fct;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
{
|
}
|
||||||
GCstr *s = lj_ctype_repr(cts->L, ctype_typeid(cts, ct), NULL);
|
if (ctype_isptr(ct->info)) { /* Automatically perform '->'. */
|
||||||
lj_err_callerv(cts->L, LJ_ERR_FFI_BADMEMBER, strdata(s), strdata(name));
|
if (ctype_isstruct(ctype_rawchild(cts, ct)->info)) {
|
||||||
|
p = (uint8_t *)cdata_getptr(p, ct->size);
|
||||||
|
ct = ctype_child(cts, ct);
|
||||||
|
goto collect_attrib;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
{
|
*qual |= 1; /* Lookup failed. */
|
||||||
GCstr *s = lj_ctype_repr(cts->L, ctype_typeid(cts, ct), NULL);
|
return ct; /* But return the resolved raw type. */
|
||||||
lj_err_callerv(cts->L, LJ_ERR_FFI_BADIDX, strdata(s));
|
|
||||||
}
|
|
||||||
return NULL; /* unreachable */
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* -- C data getters ------------------------------------------------------ */
|
/* -- C data getters ------------------------------------------------------ */
|
||||||
|
153
src/lj_crecord.c
153
src/lj_crecord.c
@ -22,6 +22,7 @@
|
|||||||
#include "lj_jit.h"
|
#include "lj_jit.h"
|
||||||
#include "lj_iropt.h"
|
#include "lj_iropt.h"
|
||||||
#include "lj_trace.h"
|
#include "lj_trace.h"
|
||||||
|
#include "lj_record.h"
|
||||||
#include "lj_ffrecord.h"
|
#include "lj_ffrecord.h"
|
||||||
#include "lj_crecord.h"
|
#include "lj_crecord.h"
|
||||||
#include "lj_dispatch.h"
|
#include "lj_dispatch.h"
|
||||||
@ -459,6 +460,41 @@ static TRef crec_reassoc_ofs(jit_State *J, TRef tr, ptrdiff_t *ofsp, MSize sz)
|
|||||||
return tr;
|
return tr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Record ctype __index/__newindex metamethods. */
|
||||||
|
static void crec_index_meta(jit_State *J, CTState *cts, CType *ct,
|
||||||
|
RecordFFData *rd)
|
||||||
|
{
|
||||||
|
CTypeID id = ctype_typeid(cts, ct);
|
||||||
|
cTValue *tv = lj_ctype_meta(cts, id, rd->data ? MM_newindex : MM_index);
|
||||||
|
if (!tv)
|
||||||
|
lj_trace_err(J, LJ_TRERR_BADTYPE);
|
||||||
|
if (tvisfunc(tv)) {
|
||||||
|
J->base[-1] = lj_ir_kfunc(J, funcV(tv)) | TREF_FRAME;
|
||||||
|
rd->nres = -1; /* Pending tailcall. */
|
||||||
|
} else if (rd->data == 0 && tvistab(tv) && tref_isstr(J->base[1])) {
|
||||||
|
/* Specialize to result of __index lookup. */
|
||||||
|
cTValue *o = lj_tab_get(J->L, tabV(tv), &rd->argv[1]);
|
||||||
|
IRType t = itype2irt(o);
|
||||||
|
if (tvisgcv(o))
|
||||||
|
J->base[0] = lj_ir_kgc(J, gcV(o), t);
|
||||||
|
else if (tvisint(o))
|
||||||
|
J->base[0] = lj_ir_kint(J, intV(o));
|
||||||
|
else if (tvisnum(o))
|
||||||
|
J->base[0] = lj_ir_knumint(J, numV(o));
|
||||||
|
else if (tvisbool(o))
|
||||||
|
J->base[0] = TREF_PRI(t);
|
||||||
|
else
|
||||||
|
lj_trace_err(J, LJ_TRERR_BADTYPE);
|
||||||
|
/* Always specialize to the key. */
|
||||||
|
emitir(IRTG(IR_EQ, IRT_STR), J->base[1], lj_ir_kstr(J, strV(&rd->argv[1])));
|
||||||
|
} else {
|
||||||
|
/* NYI: resolving of non-function metamethods. */
|
||||||
|
/* NYI: non-string keys for __index table. */
|
||||||
|
/* NYI: stores to __newindex table. */
|
||||||
|
lj_trace_err(J, LJ_TRERR_BADTYPE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void LJ_FASTCALL recff_cdata_index(jit_State *J, RecordFFData *rd)
|
void LJ_FASTCALL recff_cdata_index(jit_State *J, RecordFFData *rd)
|
||||||
{
|
{
|
||||||
TRef idx, ptr = J->base[0];
|
TRef idx, ptr = J->base[0];
|
||||||
@ -477,12 +513,13 @@ void LJ_FASTCALL recff_cdata_index(jit_State *J, RecordFFData *rd)
|
|||||||
ptr = crec_reassoc_ofs(J, ptr, &ofs, 1);
|
ptr = crec_reassoc_ofs(J, ptr, &ofs, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
again:
|
||||||
idx = J->base[1];
|
idx = J->base[1];
|
||||||
if (tref_isnumber(idx)) {
|
if (tref_isnumber(idx)) {
|
||||||
idx = lj_opt_narrow_cindex(J, idx);
|
idx = lj_opt_narrow_cindex(J, idx);
|
||||||
integer_key:
|
|
||||||
if (ctype_ispointer(ct->info)) {
|
if (ctype_ispointer(ct->info)) {
|
||||||
CTSize sz;
|
CTSize sz;
|
||||||
|
integer_key:
|
||||||
if ((ct->info & CTF_COMPLEX))
|
if ((ct->info & CTF_COMPLEX))
|
||||||
idx = emitir(IRT(IR_BAND, IRT_INTP), idx, lj_ir_kintp(J, 1));
|
idx = emitir(IRT(IR_BAND, IRT_INTP), idx, lj_ir_kintp(J, 1));
|
||||||
sz = lj_ctype_size(cts, (sid = ctype_cid(ct->info)));
|
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)
|
|||||||
CType *ctk = ctype_raw(cts, cdk->typeid);
|
CType *ctk = ctype_raw(cts, cdk->typeid);
|
||||||
IRType t;
|
IRType t;
|
||||||
if (ctype_isenum(ctk->info)) ctk = ctype_child(cts, ctk);
|
if (ctype_isenum(ctk->info)) ctk = ctype_child(cts, ctk);
|
||||||
if (ctype_isinteger(ctk->info) && (t = crec_ct2irt(ctk)) != IRT_CDATA) {
|
if (ctype_ispointer(ct->info) &&
|
||||||
|
ctype_isinteger(ctk->info) && (t = crec_ct2irt(ctk)) != IRT_CDATA) {
|
||||||
if (ctk->size == 8) {
|
if (ctk->size == 8) {
|
||||||
idx = emitir(IRT(IR_FLOAD, t), idx, IRFL_CDATA_INT64);
|
idx = emitir(IRT(IR_FLOAD, t), idx, IRFL_CDATA_INT64);
|
||||||
} else {
|
} else {
|
||||||
@ -513,22 +551,15 @@ void LJ_FASTCALL recff_cdata_index(jit_State *J, RecordFFData *rd)
|
|||||||
}
|
}
|
||||||
} else if (tref_isstr(idx)) {
|
} else if (tref_isstr(idx)) {
|
||||||
GCstr *name = strV(&rd->argv[1]);
|
GCstr *name = strV(&rd->argv[1]);
|
||||||
/* Always specialize to the field name. */
|
|
||||||
emitir(IRTG(IR_EQ, IRT_STR), idx, lj_ir_kstr(J, name));
|
|
||||||
if (cd->typeid == CTID_CTYPEID)
|
if (cd->typeid == CTID_CTYPEID)
|
||||||
ct = ctype_raw(cts, crec_constructor(J, cd, ptr));
|
ct = ctype_raw(cts, crec_constructor(J, cd, ptr));
|
||||||
if (ctype_isptr(ct->info)) { /* Automatically perform '->'. */
|
if (ctype_isstruct(ct->info)) {
|
||||||
CType *cct = ctype_rawchild(cts, ct);
|
|
||||||
if (ctype_isstruct(cct->info)) {
|
|
||||||
ct = cct;
|
|
||||||
goto index_struct;
|
|
||||||
}
|
|
||||||
} else if (ctype_isstruct(ct->info)) {
|
|
||||||
CTSize fofs;
|
CTSize fofs;
|
||||||
CType *fct;
|
CType *fct;
|
||||||
index_struct:
|
|
||||||
fct = lj_ctype_getfield(cts, ct, name, &fofs);
|
fct = lj_ctype_getfield(cts, ct, name, &fofs);
|
||||||
if (fct) {
|
if (fct) {
|
||||||
|
/* Always specialize to the field name. */
|
||||||
|
emitir(IRTG(IR_EQ, IRT_STR), idx, lj_ir_kstr(J, name));
|
||||||
if (ctype_isconstval(fct->info)) {
|
if (ctype_isconstval(fct->info)) {
|
||||||
if (fct->size >= 0x80000000u &&
|
if (fct->size >= 0x80000000u &&
|
||||||
(ctype_child(cts, fct)->info & CTF_UNSIGNED)) {
|
(ctype_child(cts, fct)->info & CTF_UNSIGNED)) {
|
||||||
@ -546,11 +577,26 @@ index_struct:
|
|||||||
ofs += (ptrdiff_t)fofs;
|
ofs += (ptrdiff_t)fofs;
|
||||||
}
|
}
|
||||||
} else if (ctype_iscomplex(ct->info)) {
|
} else if (ctype_iscomplex(ct->info)) {
|
||||||
if (strdata(name)[0] == 'i') ofs += (ct->size >> 1);
|
if (name->len == 2 &&
|
||||||
sid = ctype_cid(ct->info);
|
((strdata(name)[0] == 'r' && strdata(name)[1] == 'e') ||
|
||||||
|
(strdata(name)[0] == 'i' && strdata(name)[1] == 'm'))) {
|
||||||
|
/* Always specialize to the field name. */
|
||||||
|
emitir(IRTG(IR_EQ, IRT_STR), idx, lj_ir_kstr(J, name));
|
||||||
|
if (strdata(name)[0] == 'i') ofs += (ct->size >> 1);
|
||||||
|
sid = ctype_cid(ct->info);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!sid) lj_trace_err(J, LJ_TRERR_BADTYPE);
|
if (!sid) {
|
||||||
|
if (ctype_isptr(ct->info)) { /* Automatically perform '->'. */
|
||||||
|
CType *cct = ctype_rawchild(cts, ct);
|
||||||
|
if (ctype_isstruct(cct->info)) {
|
||||||
|
ct = cct;
|
||||||
|
if (tref_isstr(idx)) goto again;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return crec_index_meta(J, cts, ct, rd);
|
||||||
|
}
|
||||||
|
|
||||||
if (ofs)
|
if (ofs)
|
||||||
ptr = emitir(IRT(IR_ADD, IRT_PTR), ptr, lj_ir_kintp(J, ofs));
|
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)
|
|||||||
J->base[0] = emitir(IRTG(IR_CNEWI, IRT_CDATA), trid, sp);
|
J->base[0] = emitir(IRTG(IR_CNEWI, IRT_CDATA), trid, sp);
|
||||||
} else {
|
} else {
|
||||||
TRef trcd = emitir(IRTG(IR_CNEW, IRT_CDATA), trid, TREF_NIL);
|
TRef trcd = emitir(IRTG(IR_CNEW, IRT_CDATA), trid, TREF_NIL);
|
||||||
|
cTValue *fin;
|
||||||
J->base[0] = trcd;
|
J->base[0] = trcd;
|
||||||
if (J->base[1] && !J->base[2] && !lj_cconv_multi_init(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;
|
||||||
@ -660,6 +707,24 @@ static void crec_alloc(jit_State *J, RecordFFData *rd, CTypeID id)
|
|||||||
crec_ct_tv(J, d, dp, lj_ir_kint(J, 0), &tv);
|
crec_ct_tv(J, d, dp, lj_ir_kint(J, 0), &tv);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
/* Handle __gc metamethod. */
|
||||||
|
fin = lj_ctype_meta(cts, id, MM_gc);
|
||||||
|
if (fin) {
|
||||||
|
RecordIndex ix;
|
||||||
|
ix.idxchain = 0;
|
||||||
|
settabV(J->L, &ix.tabv, cts->finalizer);
|
||||||
|
ix.tab = lj_ir_ktab(J, cts->finalizer);
|
||||||
|
setboolV(&ix.keyv, 0); /* The key is new. Dummy value is ok here. */
|
||||||
|
ix.key = trcd;
|
||||||
|
copyTV(J->L, &ix.valv, fin);
|
||||||
|
if (tvisfunc(fin))
|
||||||
|
ix.val = lj_ir_kfunc(J, funcV(fin));
|
||||||
|
else if (tviscdata(fin))
|
||||||
|
ix.val = lj_ir_kgc(J, obj2gco(cdataV(fin)), IRT_CDATA);
|
||||||
|
else
|
||||||
|
lj_trace_err(J, LJ_TRERR_BADTYPE);
|
||||||
|
lj_record_idx(J, &ix);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -849,6 +914,27 @@ static TRef crec_arith_ptr(jit_State *J, TRef *sp, CType **s, MMS mm)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Record ctype arithmetic metamethods. */
|
||||||
|
static void crec_arith_meta(jit_State *J, CTState *cts, RecordFFData *rd)
|
||||||
|
{
|
||||||
|
cTValue *tv = NULL;
|
||||||
|
if (J->base[0]) {
|
||||||
|
if (tviscdata(&rd->argv[0]))
|
||||||
|
tv = lj_ctype_meta(cts, argv2cdata(J, J->base[0], &rd->argv[0])->typeid,
|
||||||
|
(MMS)rd->data);
|
||||||
|
if (!tv && J->base[1] && tviscdata(&rd->argv[1]))
|
||||||
|
tv = lj_ctype_meta(cts, argv2cdata(J, J->base[1], &rd->argv[1])->typeid,
|
||||||
|
(MMS)rd->data);
|
||||||
|
}
|
||||||
|
if (tv && tvisfunc(tv)) {
|
||||||
|
J->base[-1] = lj_ir_kfunc(J, funcV(tv)) | TREF_FRAME;
|
||||||
|
rd->nres = -1; /* Pending tailcall. */
|
||||||
|
} else {
|
||||||
|
/* NYI: non-function metamethods. */
|
||||||
|
lj_trace_err(J, LJ_TRERR_BADTYPE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void LJ_FASTCALL recff_cdata_arith(jit_State *J, RecordFFData *rd)
|
void LJ_FASTCALL recff_cdata_arith(jit_State *J, RecordFFData *rd)
|
||||||
{
|
{
|
||||||
CTState *cts = ctype_ctsG(J2G(J));
|
CTState *cts = ctype_ctsG(J2G(J));
|
||||||
@ -858,7 +944,9 @@ void LJ_FASTCALL recff_cdata_arith(jit_State *J, RecordFFData *rd)
|
|||||||
for (i = 0; i < 2; i++) {
|
for (i = 0; i < 2; i++) {
|
||||||
TRef tr = J->base[i];
|
TRef tr = J->base[i];
|
||||||
CType *ct = ctype_get(cts, CTID_DOUBLE);
|
CType *ct = ctype_get(cts, CTID_DOUBLE);
|
||||||
if (tref_iscdata(tr)) {
|
if (!tr) {
|
||||||
|
goto trymeta;
|
||||||
|
} else if (tref_iscdata(tr)) {
|
||||||
CTypeID id = argv2cdata(J, tr, &rd->argv[i])->typeid;
|
CTypeID id = argv2cdata(J, tr, &rd->argv[i])->typeid;
|
||||||
ct = ctype_raw(cts, id);
|
ct = ctype_raw(cts, id);
|
||||||
if (ctype_isptr(ct->info)) { /* Resolve pointer or reference. */
|
if (ctype_isptr(ct->info)) { /* Resolve pointer or reference. */
|
||||||
@ -876,11 +964,11 @@ void LJ_FASTCALL recff_cdata_arith(jit_State *J, RecordFFData *rd)
|
|||||||
if (ctype_isenum(ct->info)) ct = ctype_child(cts, ct);
|
if (ctype_isenum(ct->info)) ct = ctype_child(cts, ct);
|
||||||
if (ctype_isnum(ct->info)) {
|
if (ctype_isnum(ct->info)) {
|
||||||
IRType t = crec_ct2irt(ct);
|
IRType t = crec_ct2irt(ct);
|
||||||
if (t == IRT_CDATA) goto err_type;
|
if (t == IRT_CDATA) goto trymeta;
|
||||||
if (t == IRT_I64 || t == IRT_U64) lj_needsplit(J);
|
if (t == IRT_I64 || t == IRT_U64) lj_needsplit(J);
|
||||||
tr = emitir(IRT(IR_XLOAD, t), tr, 0);
|
tr = emitir(IRT(IR_XLOAD, t), tr, 0);
|
||||||
} else if (!(ctype_isptr(ct->info) || ctype_isrefarray(ct->info))) {
|
} else if (!(ctype_isptr(ct->info) || ctype_isrefarray(ct->info))) {
|
||||||
goto err_type;
|
goto trymeta;
|
||||||
}
|
}
|
||||||
} else if (tref_isnil(tr)) {
|
} else if (tref_isnil(tr)) {
|
||||||
tr = lj_ir_kptr(J, NULL);
|
tr = lj_ir_kptr(J, NULL);
|
||||||
@ -888,7 +976,7 @@ void LJ_FASTCALL recff_cdata_arith(jit_State *J, RecordFFData *rd)
|
|||||||
} else if (tref_isinteger(tr)) {
|
} else if (tref_isinteger(tr)) {
|
||||||
ct = ctype_get(cts, CTID_INT32);
|
ct = ctype_get(cts, CTID_INT32);
|
||||||
} else if (!tref_isnum(tr)) {
|
} else if (!tref_isnum(tr)) {
|
||||||
goto err_type;
|
goto trymeta;
|
||||||
}
|
}
|
||||||
ok:
|
ok:
|
||||||
s[i] = ct;
|
s[i] = ct;
|
||||||
@ -896,21 +984,22 @@ void LJ_FASTCALL recff_cdata_arith(jit_State *J, RecordFFData *rd)
|
|||||||
}
|
}
|
||||||
{
|
{
|
||||||
TRef tr;
|
TRef tr;
|
||||||
if (!(tr = crec_arith_int64(J, sp, s, (MMS)rd->data)) &&
|
if ((tr = crec_arith_int64(J, sp, s, (MMS)rd->data)) ||
|
||||||
!(tr = crec_arith_ptr(J, sp, s, (MMS)rd->data))) {
|
(tr = crec_arith_ptr(J, sp, s, (MMS)rd->data))) {
|
||||||
err_type:
|
J->base[0] = tr;
|
||||||
lj_trace_err(J, LJ_TRERR_BADTYPE);
|
/* Fixup cdata comparisons, too. Avoids some cdata escapes. */
|
||||||
}
|
if (J->postproc == LJ_POST_FIXGUARD && frame_iscont(J->L->base-1)) {
|
||||||
/* Fixup cdata comparisons, too. Avoids some cdata escapes. */
|
const BCIns *pc = frame_contpc(J->L->base-1) - 1;
|
||||||
if (J->postproc == LJ_POST_FIXGUARD && frame_iscont(J->L->base-1)) {
|
if (bc_op(*pc) <= BC_ISNEP) {
|
||||||
const BCIns *pc = frame_contpc(J->L->base-1) - 1;
|
setframe_pc(&J2G(J)->tmptv, pc);
|
||||||
if (bc_op(*pc) <= BC_ISNEP) {
|
J2G(J)->tmptv.u32.lo = ((tref_istrue(tr) ^ bc_op(*pc)) & 1);
|
||||||
setframe_pc(&J2G(J)->tmptv, pc);
|
J->postproc = LJ_POST_FIXCOMP;
|
||||||
J2G(J)->tmptv.u32.lo = ((tref_istrue(tr) ^ bc_op(*pc)) & 1);
|
}
|
||||||
J->postproc = LJ_POST_FIXCOMP;
|
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
trymeta:
|
||||||
|
crec_arith_meta(J, cts, rd);
|
||||||
}
|
}
|
||||||
J->base[0] = tr;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -306,6 +306,22 @@ CTInfo lj_ctype_info(CTState *cts, CTypeID id, CTSize *szp)
|
|||||||
return qual;
|
return qual;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Get ctype metamethod. */
|
||||||
|
cTValue *lj_ctype_meta(CTState *cts, CTypeID id, MMS mm)
|
||||||
|
{
|
||||||
|
CType *ct = ctype_get(cts, id);
|
||||||
|
cTValue *tv;
|
||||||
|
while (ctype_isattrib(ct->info)) {
|
||||||
|
id = ctype_cid(ct->info);
|
||||||
|
ct = ctype_get(cts, id);
|
||||||
|
}
|
||||||
|
tv = lj_tab_getint(cts->metatype, (int32_t)id);
|
||||||
|
if (tv && tvistab(tv) &&
|
||||||
|
(tv = lj_tab_getstr(tabV(tv), mmname_str(cts->g, mm))) && !tvisnil(tv))
|
||||||
|
return tv;
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
/* -- C type representation ----------------------------------------------- */
|
/* -- C type representation ----------------------------------------------- */
|
||||||
|
|
||||||
/* Fixed max. length of a C type representation. */
|
/* Fixed max. length of a C type representation. */
|
||||||
|
@ -159,6 +159,7 @@ typedef struct CTState {
|
|||||||
lua_State *L; /* Lua state (needed for errors and allocations). */
|
lua_State *L; /* Lua state (needed for errors and allocations). */
|
||||||
global_State *g; /* Global state. */
|
global_State *g; /* Global state. */
|
||||||
GCtab *finalizer; /* Map of cdata to finalizer. */
|
GCtab *finalizer; /* Map of cdata to finalizer. */
|
||||||
|
GCtab *metatype; /* Map of CTypeID to metatable. */
|
||||||
CTypeID1 hash[CTHASH_SIZE]; /* Hash anchors for C type table. */
|
CTypeID1 hash[CTHASH_SIZE]; /* Hash anchors for C type table. */
|
||||||
} CTState;
|
} CTState;
|
||||||
|
|
||||||
@ -426,6 +427,7 @@ LJ_FUNC CType *lj_ctype_rawref(CTState *cts, CTypeID id);
|
|||||||
LJ_FUNC CTSize lj_ctype_size(CTState *cts, CTypeID id);
|
LJ_FUNC CTSize lj_ctype_size(CTState *cts, CTypeID id);
|
||||||
LJ_FUNC CTSize lj_ctype_vlsize(CTState *cts, CType *ct, CTSize nelem);
|
LJ_FUNC CTSize lj_ctype_vlsize(CTState *cts, CType *ct, CTSize nelem);
|
||||||
LJ_FUNC CTInfo lj_ctype_info(CTState *cts, CTypeID id, CTSize *szp);
|
LJ_FUNC CTInfo lj_ctype_info(CTState *cts, CTypeID id, CTSize *szp);
|
||||||
|
LJ_FUNC cTValue *lj_ctype_meta(CTState *cts, CTypeID id, MMS mm);
|
||||||
LJ_FUNC GCstr *lj_ctype_repr(lua_State *L, CTypeID id, GCstr *name);
|
LJ_FUNC GCstr *lj_ctype_repr(lua_State *L, CTypeID id, GCstr *name);
|
||||||
LJ_FUNC GCstr *lj_ctype_repr_int64(lua_State *L, uint64_t n, int isunsigned);
|
LJ_FUNC GCstr *lj_ctype_repr_int64(lua_State *L, uint64_t n, int isunsigned);
|
||||||
LJ_FUNC GCstr *lj_ctype_repr_complex(lua_State *L, void *sp, CTSize size);
|
LJ_FUNC GCstr *lj_ctype_repr_complex(lua_State *L, void *sp, CTSize size);
|
||||||
|
Loading…
Reference in New Issue
Block a user