summaryrefslogtreecommitdiff
path: root/src/lib_ffi.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/lib_ffi.c')
-rw-r--r--src/lib_ffi.c116
1 files changed, 108 insertions, 8 deletions
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. */