Branch data Line data Source code
1 : : /*
2 : : * This file is part of the MicroPython project, http://micropython.org/
3 : : *
4 : : * The MIT License (MIT)
5 : : *
6 : : * Copyright (c) 2013, 2014 Damien P. George
7 : : * Copyright (c) 2014-2018 Paul Sokolovsky
8 : : *
9 : : * Permission is hereby granted, free of charge, to any person obtaining a copy
10 : : * of this software and associated documentation files (the "Software"), to deal
11 : : * in the Software without restriction, including without limitation the rights
12 : : * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
13 : : * copies of the Software, and to permit persons to whom the Software is
14 : : * furnished to do so, subject to the following conditions:
15 : : *
16 : : * The above copyright notice and this permission notice shall be included in
17 : : * all copies or substantial portions of the Software.
18 : : *
19 : : * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20 : : * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 : : * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22 : : * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23 : : * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24 : : * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
25 : : * THE SOFTWARE.
26 : : */
27 : :
28 : : #include "py/runtime.h"
29 : : #include "py/binary.h"
30 : : #include "py/mperrno.h"
31 : : #include "py/objint.h"
32 : : #include "py/gc.h"
33 : :
34 : : #if MICROPY_PY_FFI
35 : :
36 : : #include <assert.h>
37 : : #include <string.h>
38 : : #include <errno.h>
39 : : #include <dlfcn.h>
40 : : #include <ffi.h>
41 : :
42 : : /*
43 : : * modffi uses character codes to encode a value type, based on "struct"
44 : : * module type codes, with some extensions and overridings.
45 : : *
46 : : * Extra/overridden typecodes:
47 : : * v - void, can be used only as return type
48 : : * P - const void*, pointer to read-only memory
49 : : * p - void*, meaning pointer to a writable memory (note that this
50 : : * clashes with struct's "p" as "Pascal string").
51 : : * s - as argument, the same as "p", as return value, causes string
52 : : * to be allocated and returned, instead of pointer value.
53 : : * O - mp_obj_t, passed as is (mostly useful as a callback param)
54 : : *
55 : : * TODO:
56 : : * C - callback function
57 : : *
58 : : * Note: all constraint specified by typecode can be not enforced at this time,
59 : : * but may be later.
60 : : */
61 : :
62 : : // This union is large enough to hold any supported argument/return value.
63 : : typedef union _ffi_union_t {
64 : : ffi_arg ffi;
65 : : unsigned char B;
66 : : unsigned short int H;
67 : : unsigned int I;
68 : : unsigned long int L;
69 : : unsigned long long int Q;
70 : : float flt;
71 : : double dbl;
72 : : } ffi_union_t;
73 : :
74 : : typedef struct _mp_obj_opaque_t {
75 : : mp_obj_base_t base;
76 : : void *val;
77 : : } mp_obj_opaque_t;
78 : :
79 : : typedef struct _mp_obj_ffimod_t {
80 : : mp_obj_base_t base;
81 : : void *handle;
82 : : } mp_obj_ffimod_t;
83 : :
84 : : typedef struct _mp_obj_ffivar_t {
85 : : mp_obj_base_t base;
86 : : void *var;
87 : : char type;
88 : : // ffi_type *type;
89 : : } mp_obj_ffivar_t;
90 : :
91 : : typedef struct _mp_obj_ffifunc_t {
92 : : mp_obj_base_t base;
93 : : void *func;
94 : : char rettype;
95 : : const char *argtypes;
96 : : ffi_cif cif;
97 : : ffi_type *params[];
98 : : } mp_obj_ffifunc_t;
99 : :
100 : : typedef struct _mp_obj_fficallback_t {
101 : : mp_obj_base_t base;
102 : : void *func;
103 : : ffi_closure *clo;
104 : : char rettype;
105 : : mp_obj_t pyfunc;
106 : : ffi_cif cif;
107 : : ffi_type *params[];
108 : : } mp_obj_fficallback_t;
109 : :
110 : : // static const mp_obj_type_t opaque_type;
111 : : static const mp_obj_type_t ffimod_type;
112 : : static const mp_obj_type_t ffifunc_type;
113 : : static const mp_obj_type_t fficallback_type;
114 : : static const mp_obj_type_t ffivar_type;
115 : :
116 : 48 : static ffi_type *char2ffi_type(char c) {
117 [ - - - + : 48 : switch (c) {
- - - - -
+ + + + -
- ]
118 : : case 'b':
119 : : return &ffi_type_schar;
120 : 0 : case 'B':
121 : 0 : return &ffi_type_uchar;
122 : 0 : case 'h':
123 : 0 : return &ffi_type_sshort;
124 : 0 : case 'H':
125 : 0 : return &ffi_type_ushort;
126 : 6 : case 'i':
127 : 6 : return &ffi_type_sint;
128 : 0 : case 'I':
129 : 0 : return &ffi_type_uint;
130 : 0 : case 'l':
131 : 0 : return &ffi_type_slong;
132 : 0 : case 'L':
133 : 0 : return &ffi_type_ulong;
134 : 0 : case 'q':
135 : 0 : return &ffi_type_sint64;
136 : 0 : case 'Q':
137 : 0 : return &ffi_type_uint64;
138 : : #if MICROPY_PY_BUILTINS_FLOAT
139 : 12 : case 'f':
140 : 12 : return &ffi_type_float;
141 : 12 : case 'd':
142 : 12 : return &ffi_type_double;
143 : : #endif
144 : 16 : case 'O': // mp_obj_t
145 : : case 'C': // (*)()
146 : : case 'P': // const void*
147 : : case 'p': // void*
148 : : case 's':
149 : 16 : return &ffi_type_pointer;
150 : 2 : case 'v':
151 : 2 : return &ffi_type_void;
152 : 0 : default:
153 : 0 : return NULL;
154 : : }
155 : : }
156 : :
157 : 32 : static ffi_type *get_ffi_type(mp_obj_t o_in) {
158 [ - + - - : 32 : if (mp_obj_is_str(o_in)) {
- - ]
159 : 32 : const char *s = mp_obj_str_get_str(o_in);
160 : 32 : ffi_type *t = char2ffi_type(*s);
161 [ + - ]: 32 : if (t != NULL) {
162 : 32 : return t;
163 : : }
164 : : }
165 : : // TODO: Support actual libffi type objects
166 : :
167 : 0 : mp_raise_TypeError(MP_ERROR_TEXT("unknown type"));
168 : : }
169 : :
170 : 46 : static mp_obj_t return_ffi_value(ffi_union_t *val, char type) {
171 [ - + + - : 46 : switch (type) {
- - - - -
+ ]
172 : 0 : case 's': {
173 : 0 : const char *s = (const char *)(intptr_t)val->ffi;
174 [ # # ]: 0 : if (!s) {
175 : : return mp_const_none;
176 : : }
177 : 0 : return mp_obj_new_str(s, strlen(s));
178 : : }
179 : : case 'v':
180 : : return mp_const_none;
181 : : #if MICROPY_PY_BUILTINS_FLOAT
182 : 22 : case 'f': {
183 : 22 : return mp_obj_new_float_from_f(val->flt);
184 : : }
185 : 22 : case 'd': {
186 : 22 : return mp_obj_new_float_from_d(val->dbl);
187 : : }
188 : : #endif
189 : 0 : case 'b':
190 : : case 'h':
191 : : case 'i':
192 : : case 'l':
193 : 0 : return mp_obj_new_int((signed)val->ffi);
194 : 0 : case 'B':
195 : : case 'H':
196 : : case 'I':
197 : : case 'L':
198 : 0 : return mp_obj_new_int_from_uint(val->ffi);
199 : 0 : case 'q':
200 : 0 : return mp_obj_new_int_from_ll(val->Q);
201 : 0 : case 'Q':
202 : 0 : return mp_obj_new_int_from_ull(val->Q);
203 : 0 : case 'O':
204 : 0 : return (mp_obj_t)(intptr_t)val->ffi;
205 : 0 : default:
206 : 0 : return mp_obj_new_int(val->ffi);
207 : : }
208 : : }
209 : :
210 : : // FFI module
211 : :
212 : 0 : static void ffimod_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) {
213 : 0 : (void)kind;
214 : 0 : mp_obj_ffimod_t *self = MP_OBJ_TO_PTR(self_in);
215 : 0 : mp_printf(print, "<ffimod %p>", self->handle);
216 : 0 : }
217 : :
218 : 0 : static mp_obj_t ffimod_close(mp_obj_t self_in) {
219 : 0 : mp_obj_ffimod_t *self = MP_OBJ_TO_PTR(self_in);
220 : 0 : dlclose(self->handle);
221 : 0 : return mp_const_none;
222 : : }
223 : : static MP_DEFINE_CONST_FUN_OBJ_1(ffimod_close_obj, ffimod_close);
224 : :
225 : 14 : static mp_obj_t make_func(mp_obj_t rettype_in, void *func, mp_obj_t argtypes_in) {
226 : 14 : const char *rettype = mp_obj_str_get_str(rettype_in);
227 : 14 : const char *argtypes = mp_obj_str_get_str(argtypes_in);
228 : :
229 : 14 : mp_int_t nparams = MP_OBJ_SMALL_INT_VALUE(mp_obj_len_maybe(argtypes_in));
230 : 14 : mp_obj_ffifunc_t *o = mp_obj_malloc_var(mp_obj_ffifunc_t, params, ffi_type *, nparams, &ffifunc_type);
231 : :
232 : 14 : o->func = func;
233 : 14 : o->rettype = *rettype;
234 : 14 : o->argtypes = argtypes;
235 : :
236 : 14 : mp_obj_iter_buf_t iter_buf;
237 : 14 : mp_obj_t iterable = mp_getiter(argtypes_in, &iter_buf);
238 : 14 : mp_obj_t item;
239 : 14 : int i = 0;
240 [ + + ]: 42 : while ((item = mp_iternext(iterable)) != MP_OBJ_STOP_ITERATION) {
241 : 28 : o->params[i++] = get_ffi_type(item);
242 : : }
243 : :
244 : 14 : int res = ffi_prep_cif(&o->cif, FFI_DEFAULT_ABI, nparams, char2ffi_type(*rettype), o->params);
245 [ - + ]: 14 : if (res != FFI_OK) {
246 : 0 : mp_raise_ValueError(MP_ERROR_TEXT("error in ffi_prep_cif"));
247 : : }
248 : :
249 : 14 : return MP_OBJ_FROM_PTR(o);
250 : : }
251 : :
252 : 14 : static mp_obj_t ffimod_func(size_t n_args, const mp_obj_t *args) {
253 : 14 : (void)n_args; // always 4
254 : 14 : mp_obj_ffimod_t *self = MP_OBJ_TO_PTR(args[0]);
255 : 14 : const char *symname = mp_obj_str_get_str(args[2]);
256 : :
257 : 14 : void *sym = dlsym(self->handle, symname);
258 [ - + ]: 14 : if (sym == NULL) {
259 : 0 : mp_raise_OSError(MP_ENOENT);
260 : : }
261 : 14 : return make_func(args[1], sym, args[3]);
262 : : }
263 : : MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(ffimod_func_obj, 4, 4, ffimod_func);
264 : :
265 : 0 : static mp_obj_t mod_ffi_func(mp_obj_t rettype, mp_obj_t addr_in, mp_obj_t argtypes) {
266 : 0 : void *addr = (void *)MP_OBJ_TO_PTR(mp_obj_int_get_truncated(addr_in));
267 : 0 : return make_func(rettype, addr, argtypes);
268 : : }
269 : : MP_DEFINE_CONST_FUN_OBJ_3(mod_ffi_func_obj, mod_ffi_func);
270 : :
271 : 20 : static void call_py_func(ffi_cif *cif, void *ret, void **args, void *user_data) {
272 : 20 : mp_obj_t pyargs[cif->nargs];
273 : 20 : mp_obj_fficallback_t *o = user_data;
274 : 20 : mp_obj_t pyfunc = o->pyfunc;
275 : :
276 [ + + ]: 60 : for (uint i = 0; i < cif->nargs; i++) {
277 : 40 : pyargs[i] = mp_obj_new_int(*(mp_int_t *)args[i]);
278 : : }
279 : 20 : mp_obj_t res = mp_call_function_n_kw(pyfunc, cif->nargs, 0, pyargs);
280 : :
281 [ + - ]: 20 : if (res != mp_const_none) {
282 : 20 : *(ffi_arg *)ret = mp_obj_int_get_truncated(res);
283 : : }
284 : 20 : }
285 : :
286 : 0 : static void call_py_func_with_lock(ffi_cif *cif, void *ret, void **args, void *user_data) {
287 : 0 : mp_obj_t pyargs[cif->nargs];
288 : 0 : mp_obj_fficallback_t *o = user_data;
289 : 0 : mp_obj_t pyfunc = o->pyfunc;
290 : 0 : nlr_buf_t nlr;
291 : :
292 : : #if MICROPY_ENABLE_SCHEDULER
293 : 0 : mp_sched_lock();
294 : : #endif
295 : 0 : gc_lock();
296 : :
297 [ # # ]: 0 : if (nlr_push(&nlr) == 0) {
298 [ # # ]: 0 : for (uint i = 0; i < cif->nargs; i++) {
299 : 0 : pyargs[i] = mp_obj_new_int(*(mp_int_t *)args[i]);
300 : : }
301 : 0 : mp_obj_t res = mp_call_function_n_kw(pyfunc, cif->nargs, 0, pyargs);
302 : :
303 [ # # ]: 0 : if (res != mp_const_none) {
304 : 0 : *(ffi_arg *)ret = mp_obj_int_get_truncated(res);
305 : : }
306 : 0 : nlr_pop();
307 : : } else {
308 : : // Uncaught exception
309 : 0 : mp_printf(MICROPY_ERROR_PRINTER, "Uncaught exception in FFI callback\n");
310 : 0 : mp_obj_print_exception(MICROPY_ERROR_PRINTER, MP_OBJ_FROM_PTR(nlr.ret_val));
311 : : }
312 : :
313 : 0 : gc_unlock();
314 : : #if MICROPY_ENABLE_SCHEDULER
315 : 0 : mp_sched_unlock();
316 : : #endif
317 : 0 : }
318 : :
319 : 2 : static mp_obj_t mod_ffi_callback(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
320 : : // first 3 args are positional: retttype, func, paramtypes.
321 : 2 : mp_obj_t rettype_in = pos_args[0];
322 : 2 : mp_obj_t func_in = pos_args[1];
323 : 2 : mp_obj_t paramtypes_in = pos_args[2];
324 : :
325 : : // arg parsing is used only for additional kwargs
326 : 2 : enum { ARG_lock };
327 : 2 : static const mp_arg_t allowed_args[] = {
328 : : { MP_QSTR_lock, MP_ARG_KW_ONLY | MP_ARG_BOOL, {.u_bool = false} },
329 : : };
330 : 2 : mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
331 : 2 : mp_arg_parse_all(n_args - 3, pos_args + 3, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
332 : 2 : bool lock_in = args[ARG_lock].u_bool;
333 : :
334 : 2 : const char *rettype = mp_obj_str_get_str(rettype_in);
335 : :
336 : 2 : mp_int_t nparams = MP_OBJ_SMALL_INT_VALUE(mp_obj_len_maybe(paramtypes_in));
337 : 2 : mp_obj_fficallback_t *o = mp_obj_malloc_var(mp_obj_fficallback_t, params, ffi_type *, nparams, &fficallback_type);
338 : :
339 : 2 : o->clo = ffi_closure_alloc(sizeof(ffi_closure), &o->func);
340 : :
341 : 2 : o->rettype = *rettype;
342 : 2 : o->pyfunc = func_in;
343 : :
344 : 2 : mp_obj_iter_buf_t iter_buf;
345 : 2 : mp_obj_t iterable = mp_getiter(paramtypes_in, &iter_buf);
346 : 2 : mp_obj_t item;
347 : 2 : int i = 0;
348 [ + + ]: 6 : while ((item = mp_iternext(iterable)) != MP_OBJ_STOP_ITERATION) {
349 : 4 : o->params[i++] = get_ffi_type(item);
350 : : }
351 : :
352 : 2 : int res = ffi_prep_cif(&o->cif, FFI_DEFAULT_ABI, nparams, char2ffi_type(*rettype), o->params);
353 [ - + ]: 2 : if (res != FFI_OK) {
354 : 0 : mp_raise_ValueError(MP_ERROR_TEXT("error in ffi_prep_cif"));
355 : : }
356 : :
357 [ + - ]: 4 : res = ffi_prep_closure_loc(o->clo, &o->cif,
358 : : lock_in? call_py_func_with_lock: call_py_func, o, o->func);
359 [ - + ]: 2 : if (res != FFI_OK) {
360 : 0 : mp_raise_ValueError(MP_ERROR_TEXT("ffi_prep_closure_loc"));
361 : : }
362 : :
363 : 2 : return MP_OBJ_FROM_PTR(o);
364 : : }
365 : : MP_DEFINE_CONST_FUN_OBJ_KW(mod_ffi_callback_obj, 3, mod_ffi_callback);
366 : :
367 : 0 : static mp_obj_t ffimod_var(mp_obj_t self_in, mp_obj_t vartype_in, mp_obj_t symname_in) {
368 : 0 : mp_obj_ffimod_t *self = MP_OBJ_TO_PTR(self_in);
369 : 0 : const char *rettype = mp_obj_str_get_str(vartype_in);
370 : 0 : const char *symname = mp_obj_str_get_str(symname_in);
371 : :
372 : 0 : void *sym = dlsym(self->handle, symname);
373 [ # # ]: 0 : if (sym == NULL) {
374 : 0 : mp_raise_OSError(MP_ENOENT);
375 : : }
376 : 0 : mp_obj_ffivar_t *o = mp_obj_malloc(mp_obj_ffivar_t, &ffivar_type);
377 : :
378 : 0 : o->var = sym;
379 : 0 : o->type = *rettype;
380 : 0 : return MP_OBJ_FROM_PTR(o);
381 : : }
382 : : MP_DEFINE_CONST_FUN_OBJ_3(ffimod_var_obj, ffimod_var);
383 : :
384 : 0 : static mp_obj_t ffimod_addr(mp_obj_t self_in, mp_obj_t symname_in) {
385 : 0 : mp_obj_ffimod_t *self = MP_OBJ_TO_PTR(self_in);
386 : 0 : const char *symname = mp_obj_str_get_str(symname_in);
387 : :
388 : 0 : void *sym = dlsym(self->handle, symname);
389 [ # # ]: 0 : if (sym == NULL) {
390 : 0 : mp_raise_OSError(MP_ENOENT);
391 : : }
392 : 0 : return mp_obj_new_int((uintptr_t)sym);
393 : : }
394 : : MP_DEFINE_CONST_FUN_OBJ_2(ffimod_addr_obj, ffimod_addr);
395 : :
396 : 20 : static mp_obj_t ffimod_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) {
397 : 20 : (void)n_args;
398 : 20 : (void)n_kw;
399 : :
400 : 20 : const char *fname = NULL;
401 [ + - ]: 20 : if (args[0] != mp_const_none) {
402 : 20 : fname = mp_obj_str_get_str(args[0]);
403 : : }
404 : 20 : void *mod = dlopen(fname, RTLD_NOW | RTLD_LOCAL);
405 : :
406 [ + + ]: 20 : if (mod == NULL) {
407 : 12 : mp_raise_OSError(errno);
408 : : }
409 : 8 : mp_obj_ffimod_t *o = mp_obj_malloc(mp_obj_ffimod_t, type);
410 : 8 : o->handle = mod;
411 : 8 : return MP_OBJ_FROM_PTR(o);
412 : : }
413 : :
414 : : static const mp_rom_map_elem_t ffimod_locals_dict_table[] = {
415 : : { MP_ROM_QSTR(MP_QSTR_func), MP_ROM_PTR(&ffimod_func_obj) },
416 : : { MP_ROM_QSTR(MP_QSTR_var), MP_ROM_PTR(&ffimod_var_obj) },
417 : : { MP_ROM_QSTR(MP_QSTR_addr), MP_ROM_PTR(&ffimod_addr_obj) },
418 : : { MP_ROM_QSTR(MP_QSTR_close), MP_ROM_PTR(&ffimod_close_obj) },
419 : : };
420 : :
421 : : static MP_DEFINE_CONST_DICT(ffimod_locals_dict, ffimod_locals_dict_table);
422 : :
423 : : static MP_DEFINE_CONST_OBJ_TYPE(
424 : : ffimod_type,
425 : : MP_QSTR_ffimod,
426 : : MP_TYPE_FLAG_NONE,
427 : : make_new, ffimod_make_new,
428 : : print, ffimod_print,
429 : : locals_dict, &ffimod_locals_dict
430 : : );
431 : :
432 : : // FFI function
433 : :
434 : 0 : static void ffifunc_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) {
435 : 0 : (void)kind;
436 : 0 : mp_obj_ffifunc_t *self = MP_OBJ_TO_PTR(self_in);
437 : 0 : mp_printf(print, "<ffifunc %p>", self->func);
438 : 0 : }
439 : :
440 : 0 : static unsigned long long ffi_get_int_value(mp_obj_t o) {
441 [ # # ]: 0 : if (mp_obj_is_small_int(o)) {
442 : 0 : return MP_OBJ_SMALL_INT_VALUE(o);
443 : : } else {
444 : 0 : unsigned long long res;
445 : 0 : mp_obj_int_to_bytes_impl(o, MP_ENDIANNESS_BIG, sizeof(res), (byte *)&res);
446 : 0 : return res;
447 : : }
448 : : }
449 : :
450 : 4 : static ffi_union_t ffi_int_obj_to_ffi_union(mp_obj_t o, const char argtype) {
451 : 4 : ffi_union_t ret;
452 [ - + ]: 4 : if ((argtype | 0x20) == 'q') {
453 : 0 : ret.Q = ffi_get_int_value(o);
454 : 0 : return ret;
455 : : } else {
456 : 4 : mp_uint_t val = mp_obj_int_get_truncated(o);
457 [ - - + - : 4 : switch (argtype) {
- ]
458 : 0 : case 'b':
459 : : case 'B':
460 : 0 : ret.B = val;
461 : 0 : break;
462 : 0 : case 'h':
463 : : case 'H':
464 : 0 : ret.H = val;
465 : 0 : break;
466 : 4 : case 'i':
467 : : case 'I':
468 : 4 : ret.I = val;
469 : 4 : break;
470 : 0 : case 'l':
471 : : case 'L':
472 : 0 : ret.L = val;
473 : 0 : break;
474 : 0 : default:
475 : 0 : ret.ffi = val;
476 : 0 : break;
477 : : }
478 : : }
479 : 4 : return ret;
480 : : }
481 : :
482 : 46 : static mp_obj_t ffifunc_call(mp_obj_t self_in, size_t n_args, size_t n_kw, const mp_obj_t *args) {
483 : 46 : (void)n_kw;
484 : 46 : mp_obj_ffifunc_t *self = MP_OBJ_TO_PTR(self_in);
485 [ - + ]: 46 : assert(n_kw == 0);
486 [ - + ]: 46 : assert(n_args == self->cif.nargs);
487 : :
488 : 46 : ffi_union_t values[n_args];
489 : 46 : void *valueptrs[n_args];
490 : 46 : const char *argtype = self->argtypes;
491 [ + + ]: 118 : for (uint i = 0; i < n_args; i++, argtype++) {
492 : 72 : mp_obj_t a = args[i];
493 [ - + ]: 72 : if (*argtype == 'O') {
494 : 0 : values[i].ffi = (ffi_arg)(intptr_t)a;
495 : : #if MICROPY_PY_BUILTINS_FLOAT
496 [ + + ]: 72 : } else if (*argtype == 'f') {
497 : 28 : values[i].flt = mp_obj_get_float_to_f(a);
498 [ + + ]: 44 : } else if (*argtype == 'd') {
499 : 28 : values[i].dbl = mp_obj_get_float_to_d(a);
500 : : #endif
501 [ + + ]: 16 : } else if (a == mp_const_none) {
502 : 4 : values[i].ffi = 0;
503 [ + + + + : 12 : } else if (mp_obj_is_int(a)) {
- + ]
504 : 4 : values[i] = ffi_int_obj_to_ffi_union(a, *argtype);
505 [ + + + - : 8 : } else if (mp_obj_is_str(a)) {
- + ]
506 : 4 : const char *s = mp_obj_str_get_str(a);
507 : 4 : values[i].ffi = (ffi_arg)(intptr_t)s;
508 [ + + ]: 4 : } else if (MP_OBJ_TYPE_HAS_SLOT(((mp_obj_base_t *)MP_OBJ_TO_PTR(a))->type, buffer)) {
509 : 2 : mp_obj_base_t *o = (mp_obj_base_t *)MP_OBJ_TO_PTR(a);
510 : 2 : mp_buffer_info_t bufinfo;
511 : 2 : int ret = MP_OBJ_TYPE_GET_SLOT(o->type, buffer)(MP_OBJ_FROM_PTR(o), &bufinfo, MP_BUFFER_READ); // TODO: MP_BUFFER_READ?
512 [ - + ]: 2 : if (ret != 0) {
513 : 0 : goto error;
514 : : }
515 : 2 : values[i].ffi = (ffi_arg)(intptr_t)bufinfo.buf;
516 [ + - + - ]: 2 : } else if (mp_obj_is_type(a, &fficallback_type)) {
517 : 2 : mp_obj_fficallback_t *p = MP_OBJ_TO_PTR(a);
518 : 2 : values[i].ffi = (ffi_arg)(intptr_t)p->func;
519 : : } else {
520 : 0 : goto error;
521 : : }
522 : 72 : valueptrs[i] = &values[i];
523 : : }
524 : :
525 : 46 : ffi_union_t retval;
526 : 46 : ffi_call(&self->cif, self->func, &retval, valueptrs);
527 : 46 : return return_ffi_value(&retval, self->rettype);
528 : :
529 : 0 : error:
530 : 0 : mp_raise_TypeError(MP_ERROR_TEXT("don't know how to pass object to native function"));
531 : : }
532 : :
533 : : static MP_DEFINE_CONST_OBJ_TYPE(
534 : : ffifunc_type,
535 : : MP_QSTR_ffifunc,
536 : : MP_TYPE_FLAG_NONE,
537 : : print, ffifunc_print,
538 : : call, ffifunc_call
539 : : );
540 : :
541 : : // FFI callback for Python function
542 : :
543 : 0 : static void fficallback_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) {
544 : 0 : (void)kind;
545 : 0 : mp_obj_fficallback_t *self = MP_OBJ_TO_PTR(self_in);
546 : 0 : mp_printf(print, "<fficallback %p>", self->func);
547 : 0 : }
548 : :
549 : 0 : static mp_obj_t fficallback_cfun(mp_obj_t self_in) {
550 : 0 : mp_obj_fficallback_t *self = MP_OBJ_TO_PTR(self_in);
551 : 0 : return mp_obj_new_int_from_ull((uintptr_t)self->func);
552 : : }
553 : : static MP_DEFINE_CONST_FUN_OBJ_1(fficallback_cfun_obj, fficallback_cfun);
554 : :
555 : : static const mp_rom_map_elem_t fficallback_locals_dict_table[] = {
556 : : { MP_ROM_QSTR(MP_QSTR_cfun), MP_ROM_PTR(&fficallback_cfun_obj) }
557 : : };
558 : : static MP_DEFINE_CONST_DICT(fficallback_locals_dict, fficallback_locals_dict_table);
559 : :
560 : : static MP_DEFINE_CONST_OBJ_TYPE(
561 : : fficallback_type,
562 : : MP_QSTR_fficallback,
563 : : MP_TYPE_FLAG_NONE,
564 : : print, fficallback_print,
565 : : locals_dict, &fficallback_locals_dict
566 : : );
567 : :
568 : : // FFI variable
569 : :
570 : 0 : static void ffivar_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) {
571 : 0 : (void)kind;
572 : 0 : mp_obj_ffivar_t *self = MP_OBJ_TO_PTR(self_in);
573 : : // Variable value printed as cast to int
574 : 0 : mp_printf(print, "<ffivar @%p: 0x%x>", self->var, *(int *)self->var);
575 : 0 : }
576 : :
577 : 0 : static mp_obj_t ffivar_get(mp_obj_t self_in) {
578 : 0 : mp_obj_ffivar_t *self = MP_OBJ_TO_PTR(self_in);
579 : 0 : return mp_binary_get_val_array(self->type, self->var, 0);
580 : : }
581 : : MP_DEFINE_CONST_FUN_OBJ_1(ffivar_get_obj, ffivar_get);
582 : :
583 : 0 : static mp_obj_t ffivar_set(mp_obj_t self_in, mp_obj_t val_in) {
584 : 0 : mp_obj_ffivar_t *self = MP_OBJ_TO_PTR(self_in);
585 : 0 : mp_binary_set_val_array(self->type, self->var, 0, val_in);
586 : 0 : return mp_const_none;
587 : : }
588 : : MP_DEFINE_CONST_FUN_OBJ_2(ffivar_set_obj, ffivar_set);
589 : :
590 : : static const mp_rom_map_elem_t ffivar_locals_dict_table[] = {
591 : : { MP_ROM_QSTR(MP_QSTR_get), MP_ROM_PTR(&ffivar_get_obj) },
592 : : { MP_ROM_QSTR(MP_QSTR_set), MP_ROM_PTR(&ffivar_set_obj) },
593 : : };
594 : :
595 : : static MP_DEFINE_CONST_DICT(ffivar_locals_dict, ffivar_locals_dict_table);
596 : :
597 : : static MP_DEFINE_CONST_OBJ_TYPE(
598 : : ffivar_type,
599 : : MP_QSTR_ffivar,
600 : : MP_TYPE_FLAG_NONE,
601 : : print, ffivar_print,
602 : : locals_dict, &ffivar_locals_dict
603 : : );
604 : :
605 : : // Generic opaque storage object (unused)
606 : :
607 : : /*
608 : : static MP_DEFINE_CONST_OBJ_TYPE(
609 : : opaque_type,
610 : : MP_QSTR_opaqueval,
611 : : MP_TYPE_FLAG_NONE,
612 : : make_new, // .print = opaque_print,
613 : : );
614 : : */
615 : :
616 : 20 : static mp_obj_t mod_ffi_open(size_t n_args, const mp_obj_t *args) {
617 : 20 : return ffimod_make_new(&ffimod_type, n_args, 0, args);
618 : : }
619 : : MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mod_ffi_open_obj, 1, 2, mod_ffi_open);
620 : :
621 : 40 : static mp_obj_t mod_ffi_as_bytearray(mp_obj_t ptr, mp_obj_t size) {
622 : 40 : return mp_obj_new_bytearray_by_ref(mp_obj_int_get_truncated(size), (void *)(uintptr_t)mp_obj_int_get_truncated(ptr));
623 : : }
624 : : MP_DEFINE_CONST_FUN_OBJ_2(mod_ffi_as_bytearray_obj, mod_ffi_as_bytearray);
625 : :
626 : : static const mp_rom_map_elem_t mp_module_ffi_globals_table[] = {
627 : : { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_ffi) },
628 : : { MP_ROM_QSTR(MP_QSTR_open), MP_ROM_PTR(&mod_ffi_open_obj) },
629 : : { MP_ROM_QSTR(MP_QSTR_callback), MP_ROM_PTR(&mod_ffi_callback_obj) },
630 : : { MP_ROM_QSTR(MP_QSTR_func), MP_ROM_PTR(&mod_ffi_func_obj) },
631 : : { MP_ROM_QSTR(MP_QSTR_as_bytearray), MP_ROM_PTR(&mod_ffi_as_bytearray_obj) },
632 : : };
633 : :
634 : : static MP_DEFINE_CONST_DICT(mp_module_ffi_globals, mp_module_ffi_globals_table);
635 : :
636 : : const mp_obj_module_t mp_module_ffi = {
637 : : .base = { &mp_type_module },
638 : : .globals = (mp_obj_dict_t *)&mp_module_ffi_globals,
639 : : };
640 : :
641 : : MP_REGISTER_MODULE(MP_QSTR_ffi, mp_module_ffi);
642 : :
643 : : #endif // MICROPY_PY_FFI
|