diff options
Diffstat (limited to 'src/lib_ffi.c')
-rw-r--r-- | src/lib_ffi.c | 116 |
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. */ | ||
101 | static 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 | |||
99 | LJLIB_CF(ffi_meta___index) LJLIB_REC(cdata_index 0) | 135 | LJLIB_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 | ||
141 | LJLIB_CF(ffi_meta___len) | 184 | LJLIB_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 | ||
156 | LJLIB_CF(ffi_meta___concat) | 199 | LJLIB_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. */ | ||
205 | static 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. */ |
162 | static int lj_cf_ffi_new(lua_State *L); | 215 | static 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 | ||
295 | LJLIB_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 | ||
524 | LJLIB_PUSH(top-7) LJLIB_SET(!) /* Store reference to weak table. */ | 597 | LJLIB_PUSH(top-8) LJLIB_SET(!) /* Store reference to metatype table. */ |
598 | |||
599 | LJLIB_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 | |||
623 | LJLIB_PUSH(top-7) LJLIB_SET(!) /* Store reference to finalizer table. */ | ||
525 | 624 | ||
526 | LJLIB_CF(ffi_gc) | 625 | LJLIB_CF(ffi_gc) |
527 | { | 626 | { |
@@ -590,6 +689,7 @@ static void ffi_register_module(lua_State *L) | |||
590 | LUALIB_API int luaopen_ffi(lua_State *L) | 689 | LUALIB_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. */ |