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_from_cstr(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((ffi_sarg)val->ffi);
194 : 0 : case 'I':
195 : : // On RV64, 32-bit values are stored as signed integers inside the
196 : : // holding register.
197 : 0 : return mp_obj_new_int_from_uint(val->ffi & 0xFFFFFFFF);
198 : 0 : case 'B':
199 : : case 'H':
200 : : case 'L':
201 : 0 : return mp_obj_new_int_from_uint(val->ffi);
202 : 0 : case 'q':
203 : 0 : return mp_obj_new_int_from_ll(val->Q);
204 : 0 : case 'Q':
205 : 0 : return mp_obj_new_int_from_ull(val->Q);
206 : 0 : case 'O':
207 : 0 : return (mp_obj_t)(intptr_t)val->ffi;
208 : 0 : default:
209 : 0 : return mp_obj_new_int(val->ffi);
210 : : }
211 : : }
212 : :
213 : : // FFI module
214 : :
215 : 0 : static void ffimod_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) {
216 : 0 : (void)kind;
217 : 0 : mp_obj_ffimod_t *self = MP_OBJ_TO_PTR(self_in);
218 : 0 : mp_printf(print, "<ffimod %p>", self->handle);
219 : 0 : }
220 : :
221 : 0 : static mp_obj_t ffimod_close(mp_obj_t self_in) {
222 : 0 : mp_obj_ffimod_t *self = MP_OBJ_TO_PTR(self_in);
223 : 0 : dlclose(self->handle);
224 : 0 : return mp_const_none;
225 : : }
226 : : static MP_DEFINE_CONST_FUN_OBJ_1(ffimod_close_obj, ffimod_close);
227 : :
228 : 14 : static mp_obj_t make_func(mp_obj_t rettype_in, void *func, mp_obj_t argtypes_in) {
229 : 14 : const char *rettype = mp_obj_str_get_str(rettype_in);
230 : 14 : const char *argtypes = mp_obj_str_get_str(argtypes_in);
231 : :
232 : 14 : mp_int_t nparams = MP_OBJ_SMALL_INT_VALUE(mp_obj_len_maybe(argtypes_in));
233 : 14 : mp_obj_ffifunc_t *o = mp_obj_malloc_var(mp_obj_ffifunc_t, params, ffi_type *, nparams, &ffifunc_type);
234 : :
235 : 14 : o->func = func;
236 : 14 : o->rettype = *rettype;
237 : 14 : o->argtypes = argtypes;
238 : :
239 : 14 : mp_obj_iter_buf_t iter_buf;
240 : 14 : mp_obj_t iterable = mp_getiter(argtypes_in, &iter_buf);
241 : 14 : mp_obj_t item;
242 : 14 : int i = 0;
243 [ + + ]: 42 : while ((item = mp_iternext(iterable)) != MP_OBJ_STOP_ITERATION) {
244 : 28 : o->params[i++] = get_ffi_type(item);
245 : : }
246 : :
247 : 14 : int res = ffi_prep_cif(&o->cif, FFI_DEFAULT_ABI, nparams, char2ffi_type(*rettype), o->params);
248 [ - + ]: 14 : if (res != FFI_OK) {
249 : 0 : mp_raise_ValueError(MP_ERROR_TEXT("error in ffi_prep_cif"));
250 : : }
251 : :
252 : 14 : return MP_OBJ_FROM_PTR(o);
253 : : }
254 : :
255 : 14 : static mp_obj_t ffimod_func(size_t n_args, const mp_obj_t *args) {
256 : 14 : (void)n_args; // always 4
257 : 14 : mp_obj_ffimod_t *self = MP_OBJ_TO_PTR(args[0]);
258 : 14 : const char *symname = mp_obj_str_get_str(args[2]);
259 : :
260 : 14 : void *sym = dlsym(self->handle, symname);
261 [ - + ]: 14 : if (sym == NULL) {
262 : 0 : mp_raise_OSError(MP_ENOENT);
263 : : }
264 : 14 : return make_func(args[1], sym, args[3]);
265 : : }
266 : : MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(ffimod_func_obj, 4, 4, ffimod_func);
267 : :
268 : 0 : static mp_obj_t mod_ffi_func(mp_obj_t rettype, mp_obj_t addr_in, mp_obj_t argtypes) {
269 : 0 : void *addr = (void *)MP_OBJ_TO_PTR(mp_obj_int_get_truncated(addr_in));
270 : 0 : return make_func(rettype, addr, argtypes);
271 : : }
272 : : MP_DEFINE_CONST_FUN_OBJ_3(mod_ffi_func_obj, mod_ffi_func);
273 : :
274 : 20 : static void call_py_func(ffi_cif *cif, void *ret, void **args, void *user_data) {
275 : 20 : mp_obj_t pyargs[cif->nargs];
276 : 20 : mp_obj_fficallback_t *o = user_data;
277 : 20 : mp_obj_t pyfunc = o->pyfunc;
278 : :
279 [ + + ]: 60 : for (uint i = 0; i < cif->nargs; i++) {
280 : 40 : pyargs[i] = mp_obj_new_int(*(mp_int_t *)args[i]);
281 : : }
282 : 20 : mp_obj_t res = mp_call_function_n_kw(pyfunc, cif->nargs, 0, pyargs);
283 : :
284 [ + - ]: 20 : if (res != mp_const_none) {
285 : 20 : *(ffi_arg *)ret = mp_obj_int_get_truncated(res);
286 : : }
287 : 20 : }
288 : :
289 : 0 : static void call_py_func_with_lock(ffi_cif *cif, void *ret, void **args, void *user_data) {
290 : 0 : mp_obj_t pyargs[cif->nargs];
291 : 0 : mp_obj_fficallback_t *o = user_data;
292 : 0 : mp_obj_t pyfunc = o->pyfunc;
293 : 0 : nlr_buf_t nlr;
294 : :
295 : : #if MICROPY_ENABLE_SCHEDULER
296 : 0 : mp_sched_lock();
297 : : #endif
298 : 0 : gc_lock();
299 : :
300 [ # # ]: 0 : if (nlr_push(&nlr) == 0) {
301 [ # # ]: 0 : for (uint i = 0; i < cif->nargs; i++) {
302 : 0 : pyargs[i] = mp_obj_new_int(*(mp_int_t *)args[i]);
303 : : }
304 : 0 : mp_obj_t res = mp_call_function_n_kw(pyfunc, cif->nargs, 0, pyargs);
305 : :
306 [ # # ]: 0 : if (res != mp_const_none) {
307 : 0 : *(ffi_arg *)ret = mp_obj_int_get_truncated(res);
308 : : }
309 : 0 : nlr_pop();
310 : : } else {
311 : : // Uncaught exception
312 : 0 : mp_printf(MICROPY_ERROR_PRINTER, "Uncaught exception in FFI callback\n");
313 : 0 : mp_obj_print_exception(MICROPY_ERROR_PRINTER, MP_OBJ_FROM_PTR(nlr.ret_val));
314 : : }
315 : :
316 : 0 : gc_unlock();
317 : : #if MICROPY_ENABLE_SCHEDULER
318 : 0 : mp_sched_unlock();
319 : : #endif
320 : 0 : }
321 : :
322 : 2 : static mp_obj_t mod_ffi_callback(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
323 : : // first 3 args are positional: retttype, func, paramtypes.
324 : 2 : mp_obj_t rettype_in = pos_args[0];
325 : 2 : mp_obj_t func_in = pos_args[1];
326 : 2 : mp_obj_t paramtypes_in = pos_args[2];
327 : :
328 : : // arg parsing is used only for additional kwargs
329 : 2 : enum { ARG_lock };
330 : 2 : static const mp_arg_t allowed_args[] = {
331 : : { MP_QSTR_lock, MP_ARG_KW_ONLY | MP_ARG_BOOL, {.u_bool = false} },
332 : : };
333 : 2 : mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
334 : 2 : mp_arg_parse_all(n_args - 3, pos_args + 3, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
335 : 2 : bool lock_in = args[ARG_lock].u_bool;
336 : :
337 : 2 : const char *rettype = mp_obj_str_get_str(rettype_in);
338 : :
339 : 2 : mp_int_t nparams = MP_OBJ_SMALL_INT_VALUE(mp_obj_len_maybe(paramtypes_in));
340 : 2 : mp_obj_fficallback_t *o = (mp_obj_fficallback_t *)m_tracked_calloc(offsetof(mp_obj_fficallback_t, params) + sizeof(ffi_type *) * nparams, sizeof(uint8_t));
341 : 2 : o->base.type = &fficallback_type;
342 : :
343 : 2 : o->clo = ffi_closure_alloc(sizeof(ffi_closure), &o->func);
344 : :
345 : 2 : o->rettype = *rettype;
346 : 2 : o->pyfunc = func_in;
347 : :
348 : 2 : mp_obj_iter_buf_t iter_buf;
349 : 2 : mp_obj_t iterable = mp_getiter(paramtypes_in, &iter_buf);
350 : 2 : mp_obj_t item;
351 : 2 : int i = 0;
352 [ + + ]: 6 : while ((item = mp_iternext(iterable)) != MP_OBJ_STOP_ITERATION) {
353 : 4 : o->params[i++] = get_ffi_type(item);
354 : : }
355 : :
356 : 2 : int res = ffi_prep_cif(&o->cif, FFI_DEFAULT_ABI, nparams, char2ffi_type(*rettype), o->params);
357 [ - + ]: 2 : if (res != FFI_OK) {
358 : 0 : mp_raise_ValueError(MP_ERROR_TEXT("error in ffi_prep_cif"));
359 : : }
360 : :
361 [ + - ]: 4 : res = ffi_prep_closure_loc(o->clo, &o->cif,
362 : : lock_in? call_py_func_with_lock: call_py_func, o, o->func);
363 [ - + ]: 2 : if (res != FFI_OK) {
364 : 0 : mp_raise_ValueError(MP_ERROR_TEXT("ffi_prep_closure_loc"));
365 : : }
366 : :
367 : 2 : return MP_OBJ_FROM_PTR(o);
368 : : }
369 : : MP_DEFINE_CONST_FUN_OBJ_KW(mod_ffi_callback_obj, 3, mod_ffi_callback);
370 : :
371 : 0 : static mp_obj_t ffimod_var(mp_obj_t self_in, mp_obj_t vartype_in, mp_obj_t symname_in) {
372 : 0 : mp_obj_ffimod_t *self = MP_OBJ_TO_PTR(self_in);
373 : 0 : const char *rettype = mp_obj_str_get_str(vartype_in);
374 : 0 : const char *symname = mp_obj_str_get_str(symname_in);
375 : :
376 : 0 : void *sym = dlsym(self->handle, symname);
377 [ # # ]: 0 : if (sym == NULL) {
378 : 0 : mp_raise_OSError(MP_ENOENT);
379 : : }
380 : 0 : mp_obj_ffivar_t *o = mp_obj_malloc(mp_obj_ffivar_t, &ffivar_type);
381 : :
382 : 0 : o->var = sym;
383 : 0 : o->type = *rettype;
384 : 0 : return MP_OBJ_FROM_PTR(o);
385 : : }
386 : : MP_DEFINE_CONST_FUN_OBJ_3(ffimod_var_obj, ffimod_var);
387 : :
388 : 0 : static mp_obj_t ffimod_addr(mp_obj_t self_in, mp_obj_t symname_in) {
389 : 0 : mp_obj_ffimod_t *self = MP_OBJ_TO_PTR(self_in);
390 : 0 : const char *symname = mp_obj_str_get_str(symname_in);
391 : :
392 : 0 : void *sym = dlsym(self->handle, symname);
393 [ # # ]: 0 : if (sym == NULL) {
394 : 0 : mp_raise_OSError(MP_ENOENT);
395 : : }
396 : 0 : return mp_obj_new_int((uintptr_t)sym);
397 : : }
398 : : MP_DEFINE_CONST_FUN_OBJ_2(ffimod_addr_obj, ffimod_addr);
399 : :
400 : 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) {
401 : 20 : (void)n_args;
402 : 20 : (void)n_kw;
403 : :
404 : 20 : const char *fname = NULL;
405 [ + - ]: 20 : if (args[0] != mp_const_none) {
406 : 20 : fname = mp_obj_str_get_str(args[0]);
407 : : }
408 : 20 : void *mod = dlopen(fname, RTLD_NOW | RTLD_LOCAL);
409 : :
410 [ + + ]: 20 : if (mod == NULL) {
411 : 12 : mp_raise_OSError(errno);
412 : : }
413 : 8 : mp_obj_ffimod_t *o = mp_obj_malloc(mp_obj_ffimod_t, type);
414 : 8 : o->handle = mod;
415 : 8 : return MP_OBJ_FROM_PTR(o);
416 : : }
417 : :
418 : : static const mp_rom_map_elem_t ffimod_locals_dict_table[] = {
419 : : { MP_ROM_QSTR(MP_QSTR_func), MP_ROM_PTR(&ffimod_func_obj) },
420 : : { MP_ROM_QSTR(MP_QSTR_var), MP_ROM_PTR(&ffimod_var_obj) },
421 : : { MP_ROM_QSTR(MP_QSTR_addr), MP_ROM_PTR(&ffimod_addr_obj) },
422 : : { MP_ROM_QSTR(MP_QSTR_close), MP_ROM_PTR(&ffimod_close_obj) },
423 : : };
424 : :
425 : : static MP_DEFINE_CONST_DICT(ffimod_locals_dict, ffimod_locals_dict_table);
426 : :
427 : : static MP_DEFINE_CONST_OBJ_TYPE(
428 : : ffimod_type,
429 : : MP_QSTR_ffimod,
430 : : MP_TYPE_FLAG_NONE,
431 : : make_new, ffimod_make_new,
432 : : print, ffimod_print,
433 : : locals_dict, &ffimod_locals_dict
434 : : );
435 : :
436 : : // FFI function
437 : :
438 : 0 : static void ffifunc_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) {
439 : 0 : (void)kind;
440 : 0 : mp_obj_ffifunc_t *self = MP_OBJ_TO_PTR(self_in);
441 : 0 : mp_printf(print, "<ffifunc %p>", self->func);
442 : 0 : }
443 : :
444 : 0 : static unsigned long long ffi_get_int_value(mp_obj_t o) {
445 [ # # ]: 0 : if (mp_obj_is_small_int(o)) {
446 : 0 : return MP_OBJ_SMALL_INT_VALUE(o);
447 : : } else {
448 : 0 : unsigned long long res;
449 : 0 : mp_obj_int_to_bytes_impl(o, MP_ENDIANNESS_BIG, sizeof(res), (byte *)&res);
450 : 0 : return res;
451 : : }
452 : : }
453 : :
454 : 4 : static ffi_union_t ffi_int_obj_to_ffi_union(mp_obj_t o, const char argtype) {
455 : 4 : ffi_union_t ret;
456 [ - + ]: 4 : if ((argtype | 0x20) == 'q') {
457 : 0 : ret.Q = ffi_get_int_value(o);
458 : 0 : return ret;
459 : : } else {
460 : 4 : mp_uint_t val = mp_obj_int_get_truncated(o);
461 [ - - + - : 4 : switch (argtype) {
- ]
462 : 0 : case 'b':
463 : : case 'B':
464 : 0 : ret.B = val;
465 : 0 : break;
466 : 0 : case 'h':
467 : : case 'H':
468 : 0 : ret.H = val;
469 : 0 : break;
470 : 4 : case 'i':
471 : : case 'I':
472 : 4 : ret.I = val;
473 : 4 : break;
474 : 0 : case 'l':
475 : : case 'L':
476 : 0 : ret.L = val;
477 : 0 : break;
478 : 0 : default:
479 : 0 : ret.ffi = val;
480 : 0 : break;
481 : : }
482 : : }
483 : 4 : return ret;
484 : : }
485 : :
486 : 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) {
487 : 46 : (void)n_kw;
488 : 46 : mp_obj_ffifunc_t *self = MP_OBJ_TO_PTR(self_in);
489 [ - + ]: 46 : assert(n_kw == 0);
490 [ - + ]: 46 : assert(n_args == self->cif.nargs);
491 : :
492 : 46 : ffi_union_t values[n_args];
493 : 46 : void *valueptrs[n_args];
494 : 46 : const char *argtype = self->argtypes;
495 [ + + ]: 118 : for (uint i = 0; i < n_args; i++, argtype++) {
496 : 72 : mp_obj_t a = args[i];
497 [ - + ]: 72 : if (*argtype == 'O') {
498 : 0 : values[i].ffi = (ffi_arg)(intptr_t)a;
499 : : #if MICROPY_PY_BUILTINS_FLOAT
500 [ + + ]: 72 : } else if (*argtype == 'f') {
501 : 28 : values[i].flt = mp_obj_get_float_to_f(a);
502 [ + + ]: 44 : } else if (*argtype == 'd') {
503 : 28 : values[i].dbl = mp_obj_get_float_to_d(a);
504 : : #endif
505 [ + + ]: 16 : } else if (a == mp_const_none) {
506 : 4 : values[i].ffi = 0;
507 [ + + + + : 12 : } else if (mp_obj_is_int(a)) {
- + ]
508 : 4 : values[i] = ffi_int_obj_to_ffi_union(a, *argtype);
509 [ + + + - : 8 : } else if (mp_obj_is_str(a)) {
- + ]
510 : 4 : const char *s = mp_obj_str_get_str(a);
511 : 4 : values[i].ffi = (ffi_arg)(intptr_t)s;
512 [ + + ]: 4 : } else if (MP_OBJ_TYPE_HAS_SLOT(((mp_obj_base_t *)MP_OBJ_TO_PTR(a))->type, buffer)) {
513 : 2 : mp_obj_base_t *o = (mp_obj_base_t *)MP_OBJ_TO_PTR(a);
514 : 2 : mp_buffer_info_t bufinfo;
515 : 2 : int ret = MP_OBJ_TYPE_GET_SLOT(o->type, buffer)(MP_OBJ_FROM_PTR(o), &bufinfo, MP_BUFFER_READ); // TODO: MP_BUFFER_READ?
516 [ - + ]: 2 : if (ret != 0) {
517 : 0 : goto error;
518 : : }
519 : 2 : values[i].ffi = (ffi_arg)(intptr_t)bufinfo.buf;
520 [ + - + - ]: 2 : } else if (mp_obj_is_type(a, &fficallback_type)) {
521 : 2 : mp_obj_fficallback_t *p = MP_OBJ_TO_PTR(a);
522 : 2 : values[i].ffi = (ffi_arg)(intptr_t)p->func;
523 : : } else {
524 : 0 : goto error;
525 : : }
526 : 72 : valueptrs[i] = &values[i];
527 : : }
528 : :
529 : 46 : ffi_union_t retval;
530 : 46 : ffi_call(&self->cif, self->func, &retval, valueptrs);
531 : 46 : return return_ffi_value(&retval, self->rettype);
532 : :
533 : 0 : error:
534 : 0 : mp_raise_TypeError(MP_ERROR_TEXT("don't know how to pass object to native function"));
535 : : }
536 : :
537 : : static MP_DEFINE_CONST_OBJ_TYPE(
538 : : ffifunc_type,
539 : : MP_QSTR_ffifunc,
540 : : MP_TYPE_FLAG_NONE,
541 : : print, ffifunc_print,
542 : : call, ffifunc_call
543 : : );
544 : :
545 : : // FFI callback for Python function
546 : :
547 : 0 : static void fficallback_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) {
548 : 0 : (void)kind;
549 : 0 : mp_obj_fficallback_t *self = MP_OBJ_TO_PTR(self_in);
550 : 0 : mp_printf(print, "<fficallback %p>", self->func);
551 : 0 : }
552 : :
553 : 0 : static mp_obj_t fficallback_cfun(mp_obj_t self_in) {
554 : 0 : mp_obj_fficallback_t *self = MP_OBJ_TO_PTR(self_in);
555 : 0 : return mp_obj_new_int_from_ull((uintptr_t)self->func);
556 : : }
557 : : static MP_DEFINE_CONST_FUN_OBJ_1(fficallback_cfun_obj, fficallback_cfun);
558 : :
559 : : static const mp_rom_map_elem_t fficallback_locals_dict_table[] = {
560 : : { MP_ROM_QSTR(MP_QSTR_cfun), MP_ROM_PTR(&fficallback_cfun_obj) }
561 : : };
562 : : static MP_DEFINE_CONST_DICT(fficallback_locals_dict, fficallback_locals_dict_table);
563 : :
564 : : static MP_DEFINE_CONST_OBJ_TYPE(
565 : : fficallback_type,
566 : : MP_QSTR_fficallback,
567 : : MP_TYPE_FLAG_NONE,
568 : : print, fficallback_print,
569 : : locals_dict, &fficallback_locals_dict
570 : : );
571 : :
572 : : // FFI variable
573 : :
574 : 0 : static void ffivar_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) {
575 : 0 : (void)kind;
576 : 0 : mp_obj_ffivar_t *self = MP_OBJ_TO_PTR(self_in);
577 : : // Variable value printed as cast to int
578 : 0 : mp_printf(print, "<ffivar @%p: 0x%x>", self->var, *(int *)self->var);
579 : 0 : }
580 : :
581 : 0 : static mp_obj_t ffivar_get(mp_obj_t self_in) {
582 : 0 : mp_obj_ffivar_t *self = MP_OBJ_TO_PTR(self_in);
583 : 0 : return mp_binary_get_val_array(self->type, self->var, 0);
584 : : }
585 : : MP_DEFINE_CONST_FUN_OBJ_1(ffivar_get_obj, ffivar_get);
586 : :
587 : 0 : static mp_obj_t ffivar_set(mp_obj_t self_in, mp_obj_t val_in) {
588 : 0 : mp_obj_ffivar_t *self = MP_OBJ_TO_PTR(self_in);
589 : 0 : mp_binary_set_val_array(self->type, self->var, 0, val_in);
590 : 0 : return mp_const_none;
591 : : }
592 : : MP_DEFINE_CONST_FUN_OBJ_2(ffivar_set_obj, ffivar_set);
593 : :
594 : : static const mp_rom_map_elem_t ffivar_locals_dict_table[] = {
595 : : { MP_ROM_QSTR(MP_QSTR_get), MP_ROM_PTR(&ffivar_get_obj) },
596 : : { MP_ROM_QSTR(MP_QSTR_set), MP_ROM_PTR(&ffivar_set_obj) },
597 : : };
598 : :
599 : : static MP_DEFINE_CONST_DICT(ffivar_locals_dict, ffivar_locals_dict_table);
600 : :
601 : : static MP_DEFINE_CONST_OBJ_TYPE(
602 : : ffivar_type,
603 : : MP_QSTR_ffivar,
604 : : MP_TYPE_FLAG_NONE,
605 : : print, ffivar_print,
606 : : locals_dict, &ffivar_locals_dict
607 : : );
608 : :
609 : : // Generic opaque storage object (unused)
610 : :
611 : : /*
612 : : static MP_DEFINE_CONST_OBJ_TYPE(
613 : : opaque_type,
614 : : MP_QSTR_opaqueval,
615 : : MP_TYPE_FLAG_NONE,
616 : : make_new, // .print = opaque_print,
617 : : );
618 : : */
619 : :
620 : 20 : static mp_obj_t mod_ffi_open(size_t n_args, const mp_obj_t *args) {
621 : 20 : return ffimod_make_new(&ffimod_type, n_args, 0, args);
622 : : }
623 : : MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mod_ffi_open_obj, 1, 2, mod_ffi_open);
624 : :
625 : 40 : static mp_obj_t mod_ffi_as_bytearray(mp_obj_t ptr, mp_obj_t size) {
626 : 40 : return mp_obj_new_bytearray_by_ref(mp_obj_int_get_truncated(size), (void *)(uintptr_t)mp_obj_int_get_truncated(ptr));
627 : : }
628 : : MP_DEFINE_CONST_FUN_OBJ_2(mod_ffi_as_bytearray_obj, mod_ffi_as_bytearray);
629 : :
630 : : static const mp_rom_map_elem_t mp_module_ffi_globals_table[] = {
631 : : { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_ffi) },
632 : : { MP_ROM_QSTR(MP_QSTR_open), MP_ROM_PTR(&mod_ffi_open_obj) },
633 : : { MP_ROM_QSTR(MP_QSTR_callback), MP_ROM_PTR(&mod_ffi_callback_obj) },
634 : : { MP_ROM_QSTR(MP_QSTR_func), MP_ROM_PTR(&mod_ffi_func_obj) },
635 : : { MP_ROM_QSTR(MP_QSTR_as_bytearray), MP_ROM_PTR(&mod_ffi_as_bytearray_obj) },
636 : : };
637 : :
638 : : static MP_DEFINE_CONST_DICT(mp_module_ffi_globals, mp_module_ffi_globals_table);
639 : :
640 : : const mp_obj_module_t mp_module_ffi = {
641 : : .base = { &mp_type_module },
642 : : .globals = (mp_obj_dict_t *)&mp_module_ffi_globals,
643 : : };
644 : :
645 : : MP_REGISTER_MODULE(MP_QSTR_ffi, mp_module_ffi);
646 : :
647 : : #endif // MICROPY_PY_FFI
|