aboutsummaryrefslogtreecommitdiff
path: root/src/lib_ffi.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/lib_ffi.c')
-rw-r--r--src/lib_ffi.c374
1 files changed, 374 insertions, 0 deletions
diff --git a/src/lib_ffi.c b/src/lib_ffi.c
new file mode 100644
index 00000000..70d4c4a3
--- /dev/null
+++ b/src/lib_ffi.c
@@ -0,0 +1,374 @@
1/*
2** FFI library.
3** Copyright (C) 2005-2010 Mike Pall. See Copyright Notice in luajit.h
4*/
5
6#define lib_ffi_c
7#define LUA_LIB
8
9#include "lua.h"
10#include "lauxlib.h"
11#include "lualib.h"
12
13#include "lj_obj.h"
14
15#if LJ_HASFFI
16
17#include "lj_gc.h"
18#include "lj_err.h"
19#include "lj_str.h"
20#include "lj_ctype.h"
21#include "lj_cparse.h"
22#include "lj_cdata.h"
23#include "lj_cconv.h"
24#include "lj_lib.h"
25
26/* -- C type checks ------------------------------------------------------- */
27
28/* Check first argument for a C type and returns its ID. */
29static CTypeID ffi_checkctype(lua_State *L, CTState *cts)
30{
31 TValue *o = L->base;
32 if (!(o < L->top)) {
33 err_argtype:
34 lj_err_argtype(L, 1, "C type");
35 }
36 if (tvisstr(o)) { /* Parse an abstract C type declaration. */
37 GCstr *s = strV(o);
38 CPState cp;
39 int errcode;
40 cp.L = L;
41 cp.cts = cts;
42 cp.srcname = strdata(s);
43 cp.p = strdata(s);
44 cp.mode = CPARSE_MODE_ABSTRACT|CPARSE_MODE_NOIMPLICIT;
45 errcode = lj_cparse(&cp);
46 if (errcode) lj_err_throw(L, errcode); /* Propagate errors. */
47 return cp.val.id;
48 } else {
49 GCcdata *cd;
50 if (!tviscdata(o)) goto err_argtype;
51 cd = cdataV(o);
52 return cd->typeid == CTID_CTYPEID ? *(CTypeID *)cdataptr(cd) : cd->typeid;
53 }
54}
55
56/* Check argument for C data and return it. */
57static GCcdata *ffi_checkcdata(lua_State *L, int narg)
58{
59 TValue *o = L->base + narg-1;
60 if (!(o < L->top && tviscdata(o)))
61 lj_err_argt(L, narg, LUA_TCDATA);
62 return cdataV(o);
63}
64
65/* Convert argument to C pointer. */
66static void *ffi_checkptr(lua_State *L, int narg, CTypeID id)
67{
68 CTState *cts = ctype_cts(L);
69 TValue *o = L->base + narg-1;
70 void *p;
71 if (o >= L->top)
72 lj_err_arg(L, narg, LJ_ERR_NOVAL);
73 lj_cconv_ct_tv(cts, ctype_get(cts, id), (uint8_t *)&p, o, 0);
74 return p;
75}
76
77/* -- C type metamethods -------------------------------------------------- */
78
79#define LJLIB_MODULE_ffi_meta
80
81LJLIB_CF(ffi_meta___index)
82{
83 CTState *cts = ctype_cts(L);
84 CTInfo qual = 0;
85 CType *ct;
86 uint8_t *p;
87 TValue *o = L->base;
88 if (!(o+1 < L->top && tviscdata(o))) /* Also checks for presence of key. */
89 lj_err_argt(L, 1, LUA_TCDATA);
90 ct = lj_cdata_index(cts, cdataV(o), o+1, &p, &qual);
91 lj_cdata_get(cts, ct, L->top-1, p);
92 return 1;
93}
94
95LJLIB_CF(ffi_meta___newindex)
96{
97 CTState *cts = ctype_cts(L);
98 CTInfo qual = 0;
99 CType *ct;
100 uint8_t *p;
101 TValue *o = L->base;
102 if (!(o+2 < L->top && tviscdata(o))) /* Also checks for key and value. */
103 lj_err_argt(L, 1, LUA_TCDATA);
104 ct = lj_cdata_index(cts, cdataV(o), o+1, &p, &qual);
105 lj_cdata_set(cts, ct, p, o+2, qual);
106 return 0;
107}
108
109/* Forward declaration. */
110static int lj_cf_ffi_new(lua_State *L);
111
112LJLIB_CF(ffi_meta___call)
113{
114 GCcdata *cd = ffi_checkcdata(L, 1);
115 if (cd->typeid == CTID_CTYPEID)
116 return lj_cf_ffi_new(L);
117 lj_err_caller(L, LJ_ERR_FFI_NYICALL);
118 return 0; /* unreachable */
119}
120
121LJLIB_CF(ffi_meta___tostring)
122{
123 GCcdata *cd = ffi_checkcdata(L, 1);
124 const char *msg = "cdata<%s>: %p";
125 CTypeID id = cd->typeid;
126 if (id == CTID_CTYPEID) {
127 msg = "ctype<%s>";
128 id = *(CTypeID *)cdataptr(cd);
129 } else {
130 CType *ct = ctype_raw(ctype_cts(L), id);
131 if (ctype_iscomplex(ct->info)) {
132 setstrV(L, L->top-1, lj_ctype_repr_complex(L, cdataptr(cd), ct->size));
133 return 1;
134 } else if (ct->size == 8 && ctype_isinteger(ct->info)) {
135 setstrV(L, L->top-1, lj_ctype_repr_int64(L, *(uint64_t *)cdataptr(cd),
136 (ct->info & CTF_UNSIGNED)));
137 return 1;
138 }
139 }
140 lj_str_pushf(L, msg, strdata(lj_ctype_repr(L, id, NULL)), cdataptr(cd));
141 return 1;
142}
143
144#include "lj_libdef.h"
145
146/* -- FFI library functions ----------------------------------------------- */
147
148#define LJLIB_MODULE_ffi
149
150LJLIB_CF(ffi_cdef)
151{
152 GCstr *s = lj_lib_checkstr(L, 1);
153 CPState cp;
154 int errcode;
155 cp.L = L;
156 cp.cts = ctype_cts(L);
157 cp.srcname = strdata(s);
158 cp.p = strdata(s);
159 cp.mode = CPARSE_MODE_MULTI|CPARSE_MODE_DIRECT;
160 errcode = lj_cparse(&cp);
161 if (errcode) lj_err_throw(L, errcode); /* Propagate errors. */
162 lj_gc_check(L);
163 return 0;
164}
165
166LJLIB_CF(ffi_new)
167{
168 CTState *cts = ctype_cts(L);
169 CTypeID id = ffi_checkctype(L, cts);
170 CTSize sz;
171 CTInfo info = lj_ctype_info(cts, id, &sz);
172 TValue *o = L->base+1;
173 GCcdata *cd;
174 if ((info & CTF_VLA)) {
175 o++;
176 sz = lj_ctype_vlsize(cts, ctype_raw(cts, id),
177 (CTSize)lj_lib_checkint(L, 2));
178 }
179 if (sz == CTSIZE_INVALID)
180 lj_err_arg(L, 1, LJ_ERR_FFI_INVSIZE);
181 if (!(info & CTF_VLA) && ctype_align(info) <= CT_MEMALIGN)
182 cd = lj_cdata_new(cts, id, sz);
183 else
184 cd = lj_cdata_newv(cts, id, sz, ctype_align(info));
185 setcdataV(L, o-1, cd); /* Anchor the uninitialized cdata. */
186 lj_cconv_ct_init(cts, ctype_raw(cts, id), sz, cdataptr(cd),
187 o, (MSize)(L->top - o)); /* Initialize cdata. */
188 L->top = o; /* Only return the cdata itself. */
189 lj_gc_check(L);
190 return 1;
191}
192
193LJLIB_CF(ffi_typeof)
194{
195 CTState *cts = ctype_cts(L);
196 CTypeID id = ffi_checkctype(L, cts);
197 GCcdata *cd = lj_cdata_new(cts, CTID_CTYPEID, 4);
198 *(CTypeID *)cdataptr(cd) = id;
199 setcdataV(L, L->top-1, cd);
200 return 1;
201}
202
203LJLIB_CF(ffi_sizeof)
204{
205 CTState *cts = ctype_cts(L);
206 CTypeID id = ffi_checkctype(L, cts);
207 CTSize sz;
208 if (LJ_UNLIKELY(tviscdata(L->base) && cdataisv(cdataV(L->base)))) {
209 sz = cdatavlen(cdataV(L->base));
210 } else {
211 CType *ct = lj_ctype_rawref(cts, id);
212 if (ctype_isvltype(ct->info))
213 sz = lj_ctype_vlsize(cts, ct, (CTSize)lj_lib_checkint(L, 2));
214 else
215 sz = ctype_hassize(ct->info) ? ct->size : CTSIZE_INVALID;
216 if (LJ_UNLIKELY(sz == CTSIZE_INVALID)) {
217 setnilV(L->top-1);
218 return 1;
219 }
220 }
221 setintV(L->top-1, (int32_t)sz);
222 return 1;
223}
224
225LJLIB_CF(ffi_alignof)
226{
227 CTState *cts = ctype_cts(L);
228 CTypeID id = ffi_checkctype(L, cts);
229 CTSize sz = 0;
230 CTInfo info = lj_ctype_info(cts, id, &sz);
231 setintV(L->top-1, 1 << ctype_align(info));
232 return 1;
233}
234
235LJLIB_CF(ffi_offsetof)
236{
237 CTState *cts = ctype_cts(L);
238 CTypeID id = ffi_checkctype(L, cts);
239 GCstr *name = lj_lib_checkstr(L, 2);
240 CType *ct = lj_ctype_rawref(cts, id);
241 CTSize ofs;
242 if (ctype_isstruct(ct->info) && ct->size != CTSIZE_INVALID) {
243 CType *fct = lj_ctype_getfield(cts, ct, name, &ofs);
244 if (fct) {
245 setintV(L->top-1, ofs);
246 if (ctype_isfield(fct->info)) {
247 return 1;
248 } else if (ctype_isbitfield(fct->info)) {
249 setintV(L->top++, ctype_bitpos(fct->info));
250 setintV(L->top++, ctype_bitbsz(fct->info));
251 return 3;
252 }
253 }
254 }
255 return 0;
256}
257
258LJLIB_CF(ffi_cast)
259{
260 CTState *cts = ctype_cts(L);
261 CTypeID id = ffi_checkctype(L, cts);
262 TValue *o = lj_lib_checkany(L, 2);
263 L->top = o+1; /* Make sure this is the last item on the stack. */
264 if (!(tviscdata(o) && cdataV(o)->typeid == id)) {
265 CTSize sz = lj_ctype_size(cts, id);
266 GCcdata *cd;
267 if (sz == CTSIZE_INVALID)
268 lj_err_caller(L, LJ_ERR_FFI_INVSIZE);
269 cd = lj_cdata_new(cts, id, sz); /* Create destination cdata. */
270 lj_cconv_ct_tv(cts, ctype_raw(cts, id), cdataptr(cd), o, CCF_CAST);
271 setcdataV(L, o, cd);
272 lj_gc_check(L);
273 }
274 return 1;
275}
276
277LJLIB_CF(ffi_string)
278{
279 CTState *cts = ctype_cts(L);
280 TValue *o = lj_lib_checkany(L, 1);
281 size_t sz = (size_t)(CTSize)lj_lib_optint(L, 2, (int32_t)CTSIZE_INVALID);
282 CType *ct = ctype_get(cts, sz==CTSIZE_INVALID ? CTID_P_CVOID : CTID_P_CCHAR);
283 const char *p;
284 L->top = o+1; /* Make sure this is the last item on the stack. */
285 lj_cconv_ct_tv(cts, ct, (uint8_t *)&p, o, 0);
286 if (sz == CTSIZE_INVALID) sz = strlen(p);
287 setstrV(L, o, lj_str_new(L, p, sz));
288 lj_gc_check(L);
289 return 1;
290}
291
292LJLIB_CF(ffi_copy)
293{
294 void *dp = ffi_checkptr(L, 1, CTID_P_VOID);
295 void *sp = ffi_checkptr(L, 2, CTID_P_CVOID);
296 TValue *o = L->base+1;
297 CTSize sz;
298 if (tvisstr(o) && o+1 >= L->top) {
299 sz = strV(o)->len+1; /* Copy Lua string including trailing '\0'. */
300 } else {
301 sz = (CTSize)lj_lib_checkint(L, 3);
302 if (tvisstr(o) && sz > strV(o)->len+1)
303 sz = strV(o)->len+1; /* Max. copy length is string length. */
304 }
305 memcpy(dp, sp, sz);
306 return 0;
307}
308
309LJLIB_CF(ffi_fill)
310{
311 void *dp = ffi_checkptr(L, 1, CTID_P_VOID);
312 CTSize sz = (CTSize)lj_lib_checkint(L, 2);
313 int32_t fill = lj_lib_optint(L, 3, 0);
314 memset(dp, fill, sz);
315 return 0;
316}
317
318#define H_(le, be) LJ_ENDIAN_SELECT(0x##le, 0x##be)
319
320/* Test ABI string. */
321LJLIB_CF(ffi_abi)
322{
323 GCstr *s = lj_lib_checkstr(L, 1);
324 int b = 0;
325 switch (s->hash) {
326#if LJ_64
327 case H_(849858eb,ad35fd06): b = 1; break; /* 64bit */
328#else
329 case H_(662d3c79,d0e22477): b = 1; break; /* 32bit */
330#endif
331#if LJ_ARCH_HASFPU
332 case H_(e33ee463,e33ee463): b = 1; break; /* fpu */
333#endif
334#if LJ_ABI_SOFTFP
335 case H_(61211a23,c2e8c81c): b = 1; break; /* softfp */
336#else
337 case H_(539417a8,8ce0812f): b = 1; break; /* hardfp */
338#endif
339#if LJ_ABI_EABI
340 case H_(2182df8f,f2ed1152): b = 1; break; /* eabi */
341#endif
342#if LJ_ABI_WIN
343 case H_(4ab624a8,4ab624a8): b = 1; break; /* win */
344#endif
345 case H_(3af93066,1f001464): b = 1; break; /* le/be */
346 default:
347 break;
348 }
349 setboolV(L->top-1, b);
350 return 1;
351}
352
353#undef H_
354
355LJLIB_PUSH(top-3) LJLIB_SET(os)
356LJLIB_PUSH(top-2) LJLIB_SET(arch)
357
358#include "lj_libdef.h"
359
360/* ------------------------------------------------------------------------ */
361
362LUALIB_API int luaopen_ffi(lua_State *L)
363{
364 lj_ctype_init(L);
365 LJ_LIB_REG_(L, NULL, ffi_meta);
366 /* NOBARRIER: basemt is a GC root. */
367 setgcref(basemt_it(G(L), LJ_TCDATA), obj2gco(tabV(L->top-1)));
368 lua_pushliteral(L, LJ_OS_NAME);
369 lua_pushliteral(L, LJ_ARCH_NAME);
370 LJ_LIB_REG_(L, NULL, ffi); /* Note: no global "ffi" created! */
371 return 1;
372}
373
374#endif