Support calling foreign functions of 10 arguments or more.
[bpt/guile.git] / libguile / foreign.c
1 /* Copyright (C) 2010, 2011, 2012, 2013 Free Software Foundation, Inc.
2 *
3 * This library is free software; you can redistribute it and/or
4 * modify it under the terms of the GNU Lesser General Public License
5 * as published by the Free Software Foundation; either version 3 of
6 * the License, or (at your option) any later version.
7 *
8 * This library is distributed in the hope that it will be useful, but
9 * WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11 * Lesser General Public License for more details.
12 *
13 * You should have received a copy of the GNU Lesser General Public
14 * License along with this library; if not, write to the Free Software
15 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
16 * 02110-1301 USA
17 */
18
19 #if HAVE_CONFIG_H
20 # include <config.h>
21 #endif
22
23 #include <ffi.h>
24
25 #include <alloca.h>
26 #include <alignof.h>
27 #include <string.h>
28 #include <assert.h>
29
30 #include "libguile/_scm.h"
31 #include "libguile/bytevectors.h"
32 #include "libguile/instructions.h"
33 #include "libguile/threads.h"
34 #include "libguile/foreign.h"
35
36 \f
37
38 SCM_SYMBOL (sym_void, "void");
39 SCM_SYMBOL (sym_float, "float");
40 SCM_SYMBOL (sym_double, "double");
41 SCM_SYMBOL (sym_uint8, "uint8");
42 SCM_SYMBOL (sym_int8, "int8");
43 SCM_SYMBOL (sym_uint16, "uint16");
44 SCM_SYMBOL (sym_int16, "int16");
45 SCM_SYMBOL (sym_uint32, "uint32");
46 SCM_SYMBOL (sym_int32, "int32");
47 SCM_SYMBOL (sym_uint64, "uint64");
48 SCM_SYMBOL (sym_int64, "int64");
49 SCM_SYMBOL (sym_short, "short");
50 SCM_SYMBOL (sym_int, "int");
51 SCM_SYMBOL (sym_long, "long");
52 SCM_SYMBOL (sym_unsigned_short, "unsigned-short");
53 SCM_SYMBOL (sym_unsigned_int, "unsigned-int");
54 SCM_SYMBOL (sym_unsigned_long, "unsigned-long");
55 SCM_SYMBOL (sym_size_t, "size_t");
56 SCM_SYMBOL (sym_ssize_t, "ssize_t");
57 SCM_SYMBOL (sym_ptrdiff_t, "ptrdiff_t");
58
59 /* that's for pointers, you know. */
60 SCM_SYMBOL (sym_asterisk, "*");
61
62 SCM_SYMBOL (sym_null, "%null-pointer");
63 SCM_SYMBOL (sym_null_pointer_error, "null-pointer-error");
64
65 /* The cell representing the null pointer. */
66 static SCM null_pointer;
67
68 #if SIZEOF_VOID_P == 4
69 # define scm_to_uintptr scm_to_uint32
70 # define scm_from_uintptr scm_from_uint32
71 #elif SIZEOF_VOID_P == 8
72 # define scm_to_uintptr scm_to_uint64
73 # define scm_from_uintptr scm_from_uint64
74 #else
75 # error unsupported pointer size
76 #endif
77
78
79 /* Raise a null pointer dereference error. */
80 static void
81 null_pointer_error (const char *func_name)
82 {
83 scm_error (sym_null_pointer_error, func_name,
84 "null pointer dereference", SCM_EOL, SCM_EOL);
85 }
86
87 \f
88 static SCM cif_to_procedure (SCM cif, SCM func_ptr);
89
90
91 static SCM pointer_weak_refs = SCM_BOOL_F;
92 static scm_i_pthread_mutex_t weak_refs_lock = SCM_I_PTHREAD_MUTEX_INITIALIZER;
93
94
95 static void
96 register_weak_reference (SCM from, SCM to)
97 {
98 scm_i_pthread_mutex_lock (&weak_refs_lock);
99 scm_hashq_set_x (pointer_weak_refs, from, to);
100 scm_i_pthread_mutex_unlock (&weak_refs_lock);
101 }
102
103 static void
104 pointer_finalizer_trampoline (void *ptr, void *data)
105 {
106 scm_t_pointer_finalizer finalizer = data;
107 finalizer (SCM_POINTER_VALUE (PTR2SCM (ptr)));
108 }
109
110 SCM_DEFINE (scm_pointer_p, "pointer?", 1, 0, 0,
111 (SCM obj),
112 "Return @code{#t} if @var{obj} is a pointer object, "
113 "@code{#f} otherwise.\n")
114 #define FUNC_NAME s_scm_pointer_p
115 {
116 return scm_from_bool (SCM_POINTER_P (obj));
117 }
118 #undef FUNC_NAME
119
120 SCM_DEFINE (scm_make_pointer, "make-pointer", 1, 1, 0,
121 (SCM address, SCM finalizer),
122 "Return a foreign pointer object pointing to @var{address}. "
123 "If @var{finalizer} is passed, it should be a pointer to a "
124 "one-argument C function that will be called when the pointer "
125 "object becomes unreachable.")
126 #define FUNC_NAME s_scm_make_pointer
127 {
128 void *c_finalizer;
129 scm_t_uintptr c_address;
130
131 c_address = scm_to_uintptr (address);
132 if (SCM_UNBNDP (finalizer))
133 c_finalizer = NULL;
134 else
135 {
136 SCM_VALIDATE_POINTER (2, finalizer);
137 c_finalizer = SCM_POINTER_VALUE (finalizer);
138 }
139
140 return scm_from_pointer ((void *) c_address, c_finalizer);
141 }
142 #undef FUNC_NAME
143
144 void *
145 scm_to_pointer (SCM pointer)
146 #define FUNC_NAME "scm_to_pointer"
147 {
148 SCM_VALIDATE_POINTER (1, pointer);
149 return SCM_POINTER_VALUE (pointer);
150 }
151 #undef FUNC_NAME
152
153 SCM
154 scm_from_pointer (void *ptr, scm_t_pointer_finalizer finalizer)
155 {
156 SCM ret;
157
158 if (ptr == NULL && finalizer == NULL)
159 ret = null_pointer;
160 else
161 {
162 ret = scm_cell (scm_tc7_pointer, (scm_t_bits) ptr);
163
164 if (finalizer)
165 scm_i_set_finalizer (SCM2PTR (ret), pointer_finalizer_trampoline,
166 finalizer);
167 }
168
169 return ret;
170 }
171
172 SCM_DEFINE (scm_pointer_address, "pointer-address", 1, 0, 0,
173 (SCM pointer),
174 "Return the numerical value of @var{pointer}.")
175 #define FUNC_NAME s_scm_pointer_address
176 {
177 SCM_VALIDATE_POINTER (1, pointer);
178
179 return scm_from_uintptr ((scm_t_uintptr) SCM_POINTER_VALUE (pointer));
180 }
181 #undef FUNC_NAME
182
183 SCM_DEFINE (scm_pointer_to_scm, "pointer->scm", 1, 0, 0,
184 (SCM pointer),
185 "Unsafely cast @var{pointer} to a Scheme object.\n"
186 "Cross your fingers!")
187 #define FUNC_NAME s_scm_pointer_to_scm
188 {
189 SCM_VALIDATE_POINTER (1, pointer);
190
191 return SCM_PACK ((scm_t_bits) SCM_POINTER_VALUE (pointer));
192 }
193 #undef FUNC_NAME
194
195 SCM_DEFINE (scm_scm_to_pointer, "scm->pointer", 1, 0, 0,
196 (SCM scm),
197 "Return a foreign pointer object with the @code{object-address}\n"
198 "of @var{scm}.")
199 #define FUNC_NAME s_scm_scm_to_pointer
200 {
201 SCM ret;
202
203 ret = scm_from_pointer ((void*) SCM_UNPACK (scm), NULL);
204 if (SCM_NIMP (ret))
205 register_weak_reference (ret, scm);
206
207 return ret;
208 }
209 #undef FUNC_NAME
210
211 SCM_DEFINE (scm_pointer_to_bytevector, "pointer->bytevector", 2, 2, 0,
212 (SCM pointer, SCM len, SCM offset, SCM uvec_type),
213 "Return a bytevector aliasing the @var{len} bytes pointed\n"
214 "to by @var{pointer}.\n\n"
215 "The user may specify an alternate default interpretation for\n"
216 "the memory by passing the @var{uvec_type} argument, to indicate\n"
217 "that the memory is an array of elements of that type.\n"
218 "@var{uvec_type} should be something that\n"
219 "@code{uniform-vector-element-type} would return, like @code{f32}\n"
220 "or @code{s16}.\n\n"
221 "When @var{offset} is passed, it specifies the offset in bytes\n"
222 "relative to @var{pointer} of the memory region aliased by the\n"
223 "returned bytevector.")
224 #define FUNC_NAME s_scm_pointer_to_bytevector
225 {
226 SCM ret;
227 scm_t_int8 *ptr;
228 size_t boffset, blen;
229 scm_t_array_element_type btype;
230
231 SCM_VALIDATE_POINTER (1, pointer);
232 ptr = SCM_POINTER_VALUE (pointer);
233
234 if (SCM_UNLIKELY (ptr == NULL))
235 null_pointer_error (FUNC_NAME);
236
237 if (SCM_UNBNDP (uvec_type))
238 btype = SCM_ARRAY_ELEMENT_TYPE_VU8;
239 else
240 {
241 int i;
242 for (i = 0; i <= SCM_ARRAY_ELEMENT_TYPE_LAST; i++)
243 if (scm_is_eq (uvec_type, scm_i_array_element_types[i]))
244 break;
245 switch (i)
246 {
247 case SCM_ARRAY_ELEMENT_TYPE_VU8:
248 case SCM_ARRAY_ELEMENT_TYPE_U8:
249 case SCM_ARRAY_ELEMENT_TYPE_S8:
250 case SCM_ARRAY_ELEMENT_TYPE_U16:
251 case SCM_ARRAY_ELEMENT_TYPE_S16:
252 case SCM_ARRAY_ELEMENT_TYPE_U32:
253 case SCM_ARRAY_ELEMENT_TYPE_S32:
254 case SCM_ARRAY_ELEMENT_TYPE_U64:
255 case SCM_ARRAY_ELEMENT_TYPE_S64:
256 case SCM_ARRAY_ELEMENT_TYPE_F32:
257 case SCM_ARRAY_ELEMENT_TYPE_F64:
258 case SCM_ARRAY_ELEMENT_TYPE_C32:
259 case SCM_ARRAY_ELEMENT_TYPE_C64:
260 btype = i;
261 break;
262 default:
263 scm_wrong_type_arg_msg (FUNC_NAME, SCM_ARG1, uvec_type,
264 "uniform vector type");
265 }
266 }
267
268 if (SCM_UNBNDP (offset))
269 boffset = 0;
270 else
271 boffset = scm_to_size_t (offset);
272
273 blen = scm_to_size_t (len);
274
275 ret = scm_c_take_typed_bytevector ((signed char *) ptr + boffset,
276 blen, btype);
277 register_weak_reference (ret, pointer);
278 return ret;
279 }
280 #undef FUNC_NAME
281
282 SCM_DEFINE (scm_bytevector_to_pointer, "bytevector->pointer", 1, 1, 0,
283 (SCM bv, SCM offset),
284 "Return a pointer pointer aliasing the memory pointed to by\n"
285 "@var{bv} or @var{offset} bytes after @var{bv} when @var{offset}\n"
286 "is passed.")
287 #define FUNC_NAME s_scm_bytevector_to_pointer
288 {
289 SCM ret;
290 signed char *ptr;
291 size_t boffset;
292
293 SCM_VALIDATE_BYTEVECTOR (1, bv);
294 ptr = SCM_BYTEVECTOR_CONTENTS (bv);
295
296 if (SCM_UNBNDP (offset))
297 boffset = 0;
298 else
299 boffset = scm_to_unsigned_integer (offset, 0,
300 SCM_BYTEVECTOR_LENGTH (bv) - 1);
301
302 ret = scm_from_pointer (ptr + boffset, NULL);
303 register_weak_reference (ret, bv);
304 return ret;
305 }
306 #undef FUNC_NAME
307
308 SCM_DEFINE (scm_set_pointer_finalizer_x, "set-pointer-finalizer!", 2, 0, 0,
309 (SCM pointer, SCM finalizer),
310 "Arrange for the C procedure wrapped by @var{finalizer} to be\n"
311 "called on the pointer wrapped by @var{pointer} when @var{pointer}\n"
312 "becomes unreachable. Note: the C procedure should not call into\n"
313 "Scheme. If you need a Scheme finalizer, use guardians.")
314 #define FUNC_NAME s_scm_set_pointer_finalizer_x
315 {
316 SCM_VALIDATE_POINTER (1, pointer);
317 SCM_VALIDATE_POINTER (2, finalizer);
318
319 scm_i_add_finalizer (SCM2PTR (pointer), pointer_finalizer_trampoline,
320 SCM_POINTER_VALUE (finalizer));
321
322 return SCM_UNSPECIFIED;
323 }
324 #undef FUNC_NAME
325
326 void
327 scm_i_pointer_print (SCM pointer, SCM port, scm_print_state *pstate)
328 {
329 scm_puts ("#<pointer 0x", port);
330 scm_uintprint (scm_to_uintptr (scm_pointer_address (pointer)), 16, port);
331 scm_putc ('>', port);
332 }
333
334 \f
335 /* Non-primitive helpers functions. These procedures could be
336 implemented in terms of the primitives above but would be inefficient
337 (heap allocation overhead, Scheme/C round trips, etc.) */
338
339 SCM_DEFINE (scm_dereference_pointer, "dereference-pointer", 1, 0, 0,
340 (SCM pointer),
341 "Assuming @var{pointer} points to a memory region that\n"
342 "holds a pointer, return this pointer.")
343 #define FUNC_NAME s_scm_dereference_pointer
344 {
345 SCM_VALIDATE_POINTER (1, pointer);
346
347 return scm_from_pointer (* (void **) SCM_POINTER_VALUE (pointer), NULL);
348 }
349 #undef FUNC_NAME
350
351 SCM_DEFINE (scm_string_to_pointer, "string->pointer", 1, 1, 0,
352 (SCM string, SCM encoding),
353 "Return a foreign pointer to a nul-terminated copy of\n"
354 "@var{string} in the given @var{encoding}, defaulting to\n"
355 "the current locale encoding. The C string is freed when\n"
356 "the returned foreign pointer becomes unreachable.\n\n"
357 "This is the Scheme equivalent of @code{scm_to_stringn}.")
358 #define FUNC_NAME s_scm_string_to_pointer
359 {
360 SCM_VALIDATE_STRING (1, string);
361
362 /* XXX: Finalizers slow down libgc; they could be avoided if
363 `scm_to_string' & co. were able to use libgc-allocated memory. */
364
365 if (SCM_UNBNDP (encoding))
366 return scm_from_pointer (scm_to_locale_string (string), free);
367 else
368 {
369 char *enc;
370 SCM ret;
371
372 SCM_VALIDATE_STRING (2, encoding);
373
374 enc = scm_to_locale_string (encoding);
375 scm_dynwind_begin (0);
376 scm_dynwind_free (enc);
377
378 ret = scm_from_pointer
379 (scm_to_stringn (string, NULL, enc,
380 scm_i_default_port_conversion_handler ()),
381 free);
382
383 scm_dynwind_end ();
384
385 return ret;
386 }
387 }
388 #undef FUNC_NAME
389
390 SCM_DEFINE (scm_pointer_to_string, "pointer->string", 1, 2, 0,
391 (SCM pointer, SCM length, SCM encoding),
392 "Return the string representing the C string pointed to by\n"
393 "@var{pointer}. If @var{length} is omitted or @code{-1}, the\n"
394 "string is assumed to be nul-terminated. Otherwise\n"
395 "@var{length} is the number of bytes in memory pointed to by\n"
396 "@var{pointer}. The C string is assumed to be in the given\n"
397 "@var{encoding}, defaulting to the current locale encoding.\n\n"
398 "This is the Scheme equivalent of @code{scm_from_stringn}.")
399 #define FUNC_NAME s_scm_pointer_to_string
400 {
401 size_t len;
402
403 SCM_VALIDATE_POINTER (1, pointer);
404
405 if (SCM_UNBNDP (length)
406 || scm_is_true (scm_eqv_p (length, scm_from_int (-1))))
407 len = (size_t)-1;
408 else
409 len = scm_to_size_t (length);
410
411 if (SCM_UNBNDP (encoding))
412 return scm_from_locale_stringn (SCM_POINTER_VALUE (pointer), len);
413 else
414 {
415 char *enc;
416 SCM ret;
417
418 SCM_VALIDATE_STRING (3, encoding);
419
420 enc = scm_to_locale_string (encoding);
421 scm_dynwind_begin (0);
422 scm_dynwind_free (enc);
423
424 ret = scm_from_stringn (SCM_POINTER_VALUE (pointer), len, enc,
425 scm_i_default_port_conversion_handler ());
426
427 scm_dynwind_end ();
428
429 return ret;
430 }
431 }
432 #undef FUNC_NAME
433
434 \f
435
436 SCM_DEFINE (scm_alignof, "alignof", 1, 0, 0, (SCM type),
437 "Return the alignment of @var{type}, in bytes.\n\n"
438 "@var{type} should be a valid C type, like @code{int}.\n"
439 "Alternately @var{type} may be the symbol @code{*}, in which\n"
440 "case the alignment of a pointer is returned. @var{type} may\n"
441 "also be a list of types, in which case the alignment of a\n"
442 "@code{struct} with ABI-conventional packing is returned.")
443 #define FUNC_NAME s_scm_alignof
444 {
445 if (SCM_I_INUMP (type))
446 {
447 switch (SCM_I_INUM (type))
448 {
449 case SCM_FOREIGN_TYPE_FLOAT:
450 return scm_from_size_t (alignof_type (float));
451 case SCM_FOREIGN_TYPE_DOUBLE:
452 return scm_from_size_t (alignof_type (double));
453 case SCM_FOREIGN_TYPE_UINT8:
454 return scm_from_size_t (alignof_type (scm_t_uint8));
455 case SCM_FOREIGN_TYPE_INT8:
456 return scm_from_size_t (alignof_type (scm_t_int8));
457 case SCM_FOREIGN_TYPE_UINT16:
458 return scm_from_size_t (alignof_type (scm_t_uint16));
459 case SCM_FOREIGN_TYPE_INT16:
460 return scm_from_size_t (alignof_type (scm_t_int16));
461 case SCM_FOREIGN_TYPE_UINT32:
462 return scm_from_size_t (alignof_type (scm_t_uint32));
463 case SCM_FOREIGN_TYPE_INT32:
464 return scm_from_size_t (alignof_type (scm_t_int32));
465 case SCM_FOREIGN_TYPE_UINT64:
466 return scm_from_size_t (alignof_type (scm_t_uint64));
467 case SCM_FOREIGN_TYPE_INT64:
468 return scm_from_size_t (alignof_type (scm_t_int64));
469 default:
470 scm_wrong_type_arg (FUNC_NAME, 1, type);
471 }
472 }
473 else if (scm_is_eq (type, sym_asterisk))
474 /* a pointer */
475 return scm_from_size_t (alignof_type (void*));
476 else if (scm_is_pair (type))
477 {
478 /* TYPE is a structure. Section 3-3 of the i386, x86_64, PowerPC,
479 and SPARC P.S. of the System V ABI all say: "Aggregates
480 (structures and arrays) and unions assume the alignment of
481 their most strictly aligned component." */
482 size_t max;
483
484 for (max = 0; scm_is_pair (type); type = SCM_CDR (type))
485 {
486 size_t align;
487
488 align = scm_to_size_t (scm_alignof (SCM_CAR (type)));
489 if (align > max)
490 max = align;
491 }
492
493 return scm_from_size_t (max);
494 }
495 else
496 scm_wrong_type_arg (FUNC_NAME, 1, type);
497 }
498 #undef FUNC_NAME
499
500 SCM_DEFINE (scm_sizeof, "sizeof", 1, 0, 0, (SCM type),
501 "Return the size of @var{type}, in bytes.\n\n"
502 "@var{type} should be a valid C type, like @code{int}.\n"
503 "Alternately @var{type} may be the symbol @code{*}, in which\n"
504 "case the size of a pointer is returned. @var{type} may also\n"
505 "be a list of types, in which case the size of a @code{struct}\n"
506 "with ABI-conventional packing is returned.")
507 #define FUNC_NAME s_scm_sizeof
508 {
509 if (SCM_I_INUMP (type))
510 {
511 switch (SCM_I_INUM (type))
512 {
513 case SCM_FOREIGN_TYPE_FLOAT:
514 return scm_from_size_t (sizeof (float));
515 case SCM_FOREIGN_TYPE_DOUBLE:
516 return scm_from_size_t (sizeof (double));
517 case SCM_FOREIGN_TYPE_UINT8:
518 return scm_from_size_t (sizeof (scm_t_uint8));
519 case SCM_FOREIGN_TYPE_INT8:
520 return scm_from_size_t (sizeof (scm_t_int8));
521 case SCM_FOREIGN_TYPE_UINT16:
522 return scm_from_size_t (sizeof (scm_t_uint16));
523 case SCM_FOREIGN_TYPE_INT16:
524 return scm_from_size_t (sizeof (scm_t_int16));
525 case SCM_FOREIGN_TYPE_UINT32:
526 return scm_from_size_t (sizeof (scm_t_uint32));
527 case SCM_FOREIGN_TYPE_INT32:
528 return scm_from_size_t (sizeof (scm_t_int32));
529 case SCM_FOREIGN_TYPE_UINT64:
530 return scm_from_size_t (sizeof (scm_t_uint64));
531 case SCM_FOREIGN_TYPE_INT64:
532 return scm_from_size_t (sizeof (scm_t_int64));
533 default:
534 scm_wrong_type_arg (FUNC_NAME, 1, type);
535 }
536 }
537 else if (scm_is_eq (type, sym_asterisk))
538 /* a pointer */
539 return scm_from_size_t (sizeof (void*));
540 else if (scm_is_pair (type))
541 {
542 /* a struct */
543 size_t off = 0;
544 while (scm_is_pair (type))
545 {
546 off = ROUND_UP (off, scm_to_size_t (scm_alignof (scm_car (type))));
547 off += scm_to_size_t (scm_sizeof (scm_car (type)));
548 type = scm_cdr (type);
549 }
550 return scm_from_size_t (off);
551 }
552 else
553 scm_wrong_type_arg (FUNC_NAME, 1, type);
554 }
555 #undef FUNC_NAME
556
557
558 /* return 1 on success, 0 on failure */
559 static int
560 parse_ffi_type (SCM type, int return_p, long *n_structs, long *n_struct_elts)
561 {
562 if (SCM_I_INUMP (type))
563 {
564 if ((SCM_I_INUM (type) < 0 )
565 || (SCM_I_INUM (type) > SCM_FOREIGN_TYPE_LAST))
566 return 0;
567 else if (SCM_I_INUM (type) == SCM_FOREIGN_TYPE_VOID && !return_p)
568 return 0;
569 else
570 return 1;
571 }
572 else if (scm_is_eq (type, sym_asterisk))
573 /* a pointer */
574 return 1;
575 else
576 {
577 long len;
578
579 len = scm_ilength (type);
580 if (len < 1)
581 return 0;
582 while (len--)
583 {
584 if (!parse_ffi_type (scm_car (type), 0, n_structs, n_struct_elts))
585 return 0;
586 (*n_struct_elts)++;
587 type = scm_cdr (type);
588 }
589 (*n_structs)++;
590 return 1;
591 }
592 }
593
594 static void
595 fill_ffi_type (SCM type, ffi_type *ftype, ffi_type ***type_ptrs,
596 ffi_type **types)
597 {
598 if (SCM_I_INUMP (type))
599 {
600 switch (SCM_I_INUM (type))
601 {
602 case SCM_FOREIGN_TYPE_FLOAT:
603 *ftype = ffi_type_float;
604 return;
605 case SCM_FOREIGN_TYPE_DOUBLE:
606 *ftype = ffi_type_double;
607 return;
608 case SCM_FOREIGN_TYPE_UINT8:
609 *ftype = ffi_type_uint8;
610 return;
611 case SCM_FOREIGN_TYPE_INT8:
612 *ftype = ffi_type_sint8;
613 return;
614 case SCM_FOREIGN_TYPE_UINT16:
615 *ftype = ffi_type_uint16;
616 return;
617 case SCM_FOREIGN_TYPE_INT16:
618 *ftype = ffi_type_sint16;
619 return;
620 case SCM_FOREIGN_TYPE_UINT32:
621 *ftype = ffi_type_uint32;
622 return;
623 case SCM_FOREIGN_TYPE_INT32:
624 *ftype = ffi_type_sint32;
625 return;
626 case SCM_FOREIGN_TYPE_UINT64:
627 *ftype = ffi_type_uint64;
628 return;
629 case SCM_FOREIGN_TYPE_INT64:
630 *ftype = ffi_type_sint64;
631 return;
632 case SCM_FOREIGN_TYPE_VOID:
633 *ftype = ffi_type_void;
634 return;
635 default:
636 scm_wrong_type_arg_msg ("pointer->procedure", 0, type,
637 "foreign type");
638 }
639 }
640 else if (scm_is_eq (type, sym_asterisk))
641 /* a pointer */
642 {
643 *ftype = ffi_type_pointer;
644 return;
645 }
646 else
647 {
648 long i, len;
649
650 len = scm_ilength (type);
651
652 ftype->size = 0;
653 ftype->alignment = 0;
654 ftype->type = FFI_TYPE_STRUCT;
655 ftype->elements = *type_ptrs;
656 *type_ptrs += len + 1;
657
658 for (i = 0; i < len; i++)
659 {
660 ftype->elements[i] = *types;
661 *types += 1;
662 fill_ffi_type (scm_car (type), ftype->elements[i],
663 type_ptrs, types);
664 type = scm_cdr (type);
665 }
666 ftype->elements[i] = NULL;
667 }
668 }
669
670 /* Return a "cif" (call interface) for the given RETURN_TYPE and
671 ARG_TYPES. */
672 static ffi_cif *
673 make_cif (SCM return_type, SCM arg_types, const char *caller)
674 #define FUNC_NAME caller
675 {
676 SCM walk;
677 long i, nargs, n_structs, n_struct_elts;
678 size_t cif_len;
679 char *mem;
680 ffi_cif *cif;
681 ffi_type **type_ptrs;
682 ffi_type *types;
683
684 nargs = scm_ilength (arg_types);
685 SCM_ASSERT (nargs >= 0, arg_types, 3, FUNC_NAME);
686 /* fixme: assert nargs < 1<<32 */
687 n_structs = n_struct_elts = 0;
688
689 /* For want of talloc, we're going to have to do this in two passes: first we
690 figure out how much memory is needed for all types, then we allocate the
691 cif and the types all in one block. */
692 if (!parse_ffi_type (return_type, 1, &n_structs, &n_struct_elts))
693 scm_wrong_type_arg (FUNC_NAME, 1, return_type);
694 for (walk = arg_types; scm_is_pair (walk); walk = scm_cdr (walk))
695 if (!parse_ffi_type (scm_car (walk), 0, &n_structs, &n_struct_elts))
696 scm_wrong_type_arg (FUNC_NAME, 3, scm_car (walk));
697
698 /* the memory: with space for the cif itself */
699 cif_len = sizeof (ffi_cif);
700
701 /* then ffi_type pointers: one for each arg, one for each struct
702 element, and one for each struct (for null-termination) */
703 cif_len = (ROUND_UP (cif_len, alignof_type (void *))
704 + (nargs + n_structs + n_struct_elts)*sizeof(void*));
705
706 /* then the ffi_type structs themselves, one per arg and struct element, and
707 one for the return val */
708 cif_len = (ROUND_UP (cif_len, alignof_type (ffi_type))
709 + (nargs + n_struct_elts + 1)*sizeof(ffi_type));
710
711 mem = scm_gc_malloc_pointerless (cif_len, "foreign");
712 /* ensure all the memory is initialized, even the holes */
713 memset (mem, 0, cif_len);
714 cif = (ffi_cif *) mem;
715
716 /* reuse cif_len to walk through the mem */
717 cif_len = ROUND_UP (sizeof (ffi_cif), alignof_type (void *));
718 type_ptrs = (ffi_type**)(mem + cif_len);
719 cif_len = ROUND_UP (cif_len
720 + (nargs + n_structs + n_struct_elts)*sizeof(void*),
721 alignof_type (ffi_type));
722 types = (ffi_type*)(mem + cif_len);
723
724 /* whew. now knit the pointers together. */
725 cif->rtype = types++;
726 fill_ffi_type (return_type, cif->rtype, &type_ptrs, &types);
727 cif->arg_types = type_ptrs;
728 type_ptrs += nargs;
729 for (walk = arg_types, i = 0; scm_is_pair (walk); walk = scm_cdr (walk), i++)
730 {
731 cif->arg_types[i] = types++;
732 fill_ffi_type (scm_car (walk), cif->arg_types[i], &type_ptrs, &types);
733 }
734
735 /* round out the cif, and we're done. */
736 cif->abi = FFI_DEFAULT_ABI;
737 cif->nargs = nargs;
738 cif->bytes = 0;
739 cif->flags = 0;
740
741 if (FFI_OK != ffi_prep_cif (cif, FFI_DEFAULT_ABI, cif->nargs, cif->rtype,
742 cif->arg_types))
743 SCM_MISC_ERROR ("ffi_prep_cif failed", SCM_EOL);
744
745 return cif;
746 }
747 #undef FUNC_NAME
748
749 SCM_DEFINE (scm_pointer_to_procedure, "pointer->procedure", 3, 0, 0,
750 (SCM return_type, SCM func_ptr, SCM arg_types),
751 "Make a foreign function.\n\n"
752 "Given the foreign void pointer @var{func_ptr}, its argument and\n"
753 "return types @var{arg_types} and @var{return_type}, return a\n"
754 "procedure that will pass arguments to the foreign function\n"
755 "and return appropriate values.\n\n"
756 "@var{arg_types} should be a list of foreign types.\n"
757 "@code{return_type} should be a foreign type.")
758 #define FUNC_NAME s_scm_pointer_to_procedure
759 {
760 ffi_cif *cif;
761
762 SCM_VALIDATE_POINTER (2, func_ptr);
763
764 cif = make_cif (return_type, arg_types, FUNC_NAME);
765
766 return cif_to_procedure (scm_from_pointer (cif, NULL), func_ptr);
767 }
768 #undef FUNC_NAME
769
770 \f
771
772 /* Pre-generate trampolines for less than 10 arguments. */
773
774 #ifdef WORDS_BIGENDIAN
775 #define OBJCODE_HEADER(M) M (0), M (0), M (0), M (8), M (0), M (0), M (0), M (40)
776 #define META_HEADER(M) M (0), M (0), M (0), M (32), M (0), M (0), M (0), M (0)
777 #else
778 #define OBJCODE_HEADER(M) M (8), M (0), M (0), M (0), M (40), M (0), M (0), M (0)
779 #define META_HEADER(M) M (32), M (0), M (0), M (0), M (0), M (0), M (0), M (0)
780 #endif
781
782 #define GEN_CODE(M, nreq) \
783 OBJCODE_HEADER (M), \
784 /* 0 */ M (scm_op_assert_nargs_ee), M (0), M (nreq), /* assert number of args */ \
785 /* 3 */ M (scm_op_object_ref), M (0), /* push the pair with the cif and the function pointer */ \
786 /* 5 */ M (scm_op_foreign_call), M (nreq), /* and call (will return value as well) */ \
787 /* 7 */ M (scm_op_nop), \
788 /* 8 */ META (M, 3, 7, nreq)
789
790 #define META(M, start, end, nreq) \
791 META_HEADER (M), \
792 /* 0 */ M (scm_op_make_eol), /* bindings */ \
793 /* 1 */ M (scm_op_make_eol), /* sources */ \
794 /* 2 */ M (scm_op_make_int8), M (start), M (scm_op_make_int8), M (end), /* arity: from ip N to ip N */ \
795 /* 6 */ M (scm_op_make_int8), M (nreq), /* the arity is N required args */ \
796 /* 8 */ M (scm_op_list), M (0), M (3), /* make a list of those 3 vals */ \
797 /* 11 */ M (scm_op_list), M (0), M (1), /* and the arities will be a list of that one list */ \
798 /* 14 */ M (scm_op_load_symbol), M (0), M (0), M (4), M ('n'), M ('a'), M ('M'), M ('e'), /* `name' */ \
799 /* 22 */ M (scm_op_object_ref), M (1), /* the name from the object table */ \
800 /* 24 */ M (scm_op_cons), /* make a pair for the properties */ \
801 /* 25 */ M (scm_op_list), M (0), M (4), /* pack bindings, sources, and arities into list */ \
802 /* 28 */ M (scm_op_return), /* and return */ \
803 /* 29 */ M (scm_op_nop), M (scm_op_nop), M (scm_op_nop) \
804 /* 32 */
805
806 #define M_STATIC(x) (x)
807 #define CODE(nreq) GEN_CODE (M_STATIC, nreq)
808
809 static const struct
810 {
811 scm_t_uint64 dummy; /* ensure 8-byte alignment; perhaps there's a better way */
812 const scm_t_uint8 bytes[10 * (sizeof (struct scm_objcode) + 8
813 + sizeof (struct scm_objcode) + 32)];
814 } raw_bytecode = {
815 0,
816 {
817 CODE (0), CODE (1), CODE (2), CODE (3), CODE (4),
818 CODE (5), CODE (6), CODE (7), CODE (8), CODE (9)
819 }
820 };
821
822 static SCM
823 make_objcode_trampoline (unsigned int nargs)
824 {
825 const int size = sizeof (struct scm_objcode) + 8
826 + sizeof (struct scm_objcode) + 32;
827 SCM bytecode = scm_c_make_bytevector (size);
828 scm_t_uint8 *bytes = (scm_t_uint8 *) SCM_BYTEVECTOR_CONTENTS (bytecode);
829 int i = 0;
830
831 #define M_DYNAMIC(x) (bytes[i++] = (x))
832 GEN_CODE (M_DYNAMIC, nargs);
833 #undef M_DYNAMIC
834
835 if (i != size)
836 scm_syserror ("make_objcode_trampoline");
837 return scm_bytecode_to_native_objcode (bytecode);
838 }
839
840 #undef GEN_CODE
841 #undef META
842 #undef M_STATIC
843 #undef CODE
844 #undef OBJCODE_HEADER
845 #undef META_HEADER
846
847 /*
848 (defun generate-objcode-cells (n)
849 "Generate objcode cells for up to N arguments"
850 (interactive "p")
851 (let ((i 0))
852 (while (< i n)
853 (insert
854 (format " { STATIC_OBJCODE_TAG, SCM_PACK (raw_bytecode.bytes + %d) },\n"
855 (* (+ 4 4 8 4 4 32) i)))
856 (insert " { SCM_BOOL_F, SCM_PACK (0) },\n")
857 (setq i (1+ i)))))
858 */
859 #define STATIC_OBJCODE_TAG \
860 SCM_PACK (SCM_MAKE_OBJCODE_TAG (SCM_OBJCODE_TYPE_STATIC, 0))
861
862 static const struct
863 {
864 scm_t_uint64 dummy; /* alignment */
865 scm_t_cell cells[10 * 2]; /* 10 double cells */
866 } objcode_cells = {
867 0,
868 /* C-u 1 0 M-x generate-objcode-cells RET */
869 {
870 { STATIC_OBJCODE_TAG, SCM_PACK (raw_bytecode.bytes + 0) },
871 { SCM_BOOL_F, SCM_PACK (0) },
872 { STATIC_OBJCODE_TAG, SCM_PACK (raw_bytecode.bytes + 56) },
873 { SCM_BOOL_F, SCM_PACK (0) },
874 { STATIC_OBJCODE_TAG, SCM_PACK (raw_bytecode.bytes + 112) },
875 { SCM_BOOL_F, SCM_PACK (0) },
876 { STATIC_OBJCODE_TAG, SCM_PACK (raw_bytecode.bytes + 168) },
877 { SCM_BOOL_F, SCM_PACK (0) },
878 { STATIC_OBJCODE_TAG, SCM_PACK (raw_bytecode.bytes + 224) },
879 { SCM_BOOL_F, SCM_PACK (0) },
880 { STATIC_OBJCODE_TAG, SCM_PACK (raw_bytecode.bytes + 280) },
881 { SCM_BOOL_F, SCM_PACK (0) },
882 { STATIC_OBJCODE_TAG, SCM_PACK (raw_bytecode.bytes + 336) },
883 { SCM_BOOL_F, SCM_PACK (0) },
884 { STATIC_OBJCODE_TAG, SCM_PACK (raw_bytecode.bytes + 392) },
885 { SCM_BOOL_F, SCM_PACK (0) },
886 { STATIC_OBJCODE_TAG, SCM_PACK (raw_bytecode.bytes + 448) },
887 { SCM_BOOL_F, SCM_PACK (0) },
888 { STATIC_OBJCODE_TAG, SCM_PACK (raw_bytecode.bytes + 504) },
889 { SCM_BOOL_F, SCM_PACK (0) }
890 }
891 };
892
893 static const SCM objcode_trampolines[10] = {
894 SCM_PACK (objcode_cells.cells+0),
895 SCM_PACK (objcode_cells.cells+2),
896 SCM_PACK (objcode_cells.cells+4),
897 SCM_PACK (objcode_cells.cells+6),
898 SCM_PACK (objcode_cells.cells+8),
899 SCM_PACK (objcode_cells.cells+10),
900 SCM_PACK (objcode_cells.cells+12),
901 SCM_PACK (objcode_cells.cells+14),
902 SCM_PACK (objcode_cells.cells+16),
903 SCM_PACK (objcode_cells.cells+18),
904 };
905
906 static SCM large_objcode_trampolines = SCM_UNDEFINED;
907 static scm_i_pthread_mutex_t large_objcode_trampolines_mutex =
908 SCM_I_PTHREAD_MUTEX_INITIALIZER;
909
910 static SCM
911 get_objcode_trampoline (unsigned int nargs)
912 {
913 SCM objcode;
914
915 if (nargs < 10)
916 objcode = objcode_trampolines[nargs];
917 else if (nargs < 128)
918 {
919 scm_i_scm_pthread_mutex_lock (&large_objcode_trampolines_mutex);
920 if (SCM_UNBNDP (large_objcode_trampolines))
921 large_objcode_trampolines = scm_c_make_vector (128, SCM_UNDEFINED);
922 objcode = scm_c_vector_ref (large_objcode_trampolines, nargs);
923 if (SCM_UNBNDP (objcode))
924 scm_c_vector_set_x (large_objcode_trampolines, nargs,
925 objcode = make_objcode_trampoline (nargs));
926 scm_i_pthread_mutex_unlock (&large_objcode_trampolines_mutex);
927 }
928 else
929 scm_misc_error ("make-foreign-function", "args >= 128 currently unimplemented",
930 SCM_EOL);
931
932 return objcode;
933 }
934
935 static SCM
936 cif_to_procedure (SCM cif, SCM func_ptr)
937 {
938 ffi_cif *c_cif;
939 SCM objcode, table, ret;
940
941 c_cif = (ffi_cif *) SCM_POINTER_VALUE (cif);
942 objcode = get_objcode_trampoline (c_cif->nargs);
943
944 table = scm_c_make_vector (2, SCM_UNDEFINED);
945 SCM_SIMPLE_VECTOR_SET (table, 0, scm_cons (cif, func_ptr));
946 SCM_SIMPLE_VECTOR_SET (table, 1, SCM_BOOL_F); /* name */
947 ret = scm_make_program (objcode, table, SCM_BOOL_F);
948
949 return ret;
950 }
951
952 /* Set *LOC to the foreign representation of X with TYPE. */
953 static void
954 unpack (const ffi_type *type, void *loc, SCM x, int return_value_p)
955 #define FUNC_NAME "scm_i_foreign_call"
956 {
957 switch (type->type)
958 {
959 case FFI_TYPE_FLOAT:
960 *(float *) loc = scm_to_double (x);
961 break;
962 case FFI_TYPE_DOUBLE:
963 *(double *) loc = scm_to_double (x);
964 break;
965
966 /* For integer return values smaller than `int', libffi expects the
967 result in an `ffi_arg'-long buffer. */
968
969 case FFI_TYPE_UINT8:
970 if (return_value_p)
971 *(ffi_arg *) loc = scm_to_uint8 (x);
972 else
973 *(scm_t_uint8 *) loc = scm_to_uint8 (x);
974 break;
975 case FFI_TYPE_SINT8:
976 if (return_value_p)
977 *(ffi_arg *) loc = scm_to_int8 (x);
978 else
979 *(scm_t_int8 *) loc = scm_to_int8 (x);
980 break;
981 case FFI_TYPE_UINT16:
982 if (return_value_p)
983 *(ffi_arg *) loc = scm_to_uint16 (x);
984 else
985 *(scm_t_uint16 *) loc = scm_to_uint16 (x);
986 break;
987 case FFI_TYPE_SINT16:
988 if (return_value_p)
989 *(ffi_arg *) loc = scm_to_int16 (x);
990 else
991 *(scm_t_int16 *) loc = scm_to_int16 (x);
992 break;
993 case FFI_TYPE_UINT32:
994 if (return_value_p)
995 *(ffi_arg *) loc = scm_to_uint32 (x);
996 else
997 *(scm_t_uint32 *) loc = scm_to_uint32 (x);
998 break;
999 case FFI_TYPE_SINT32:
1000 if (return_value_p)
1001 *(ffi_arg *) loc = scm_to_int32 (x);
1002 else
1003 *(scm_t_int32 *) loc = scm_to_int32 (x);
1004 break;
1005 case FFI_TYPE_UINT64:
1006 *(scm_t_uint64 *) loc = scm_to_uint64 (x);
1007 break;
1008 case FFI_TYPE_SINT64:
1009 *(scm_t_int64 *) loc = scm_to_int64 (x);
1010 break;
1011 case FFI_TYPE_STRUCT:
1012 SCM_VALIDATE_POINTER (1, x);
1013 memcpy (loc, SCM_POINTER_VALUE (x), type->size);
1014 break;
1015 case FFI_TYPE_POINTER:
1016 SCM_VALIDATE_POINTER (1, x);
1017 *(void **) loc = SCM_POINTER_VALUE (x);
1018 break;
1019 case FFI_TYPE_VOID:
1020 /* Do nothing. */
1021 break;
1022 default:
1023 abort ();
1024 }
1025 }
1026 #undef FUNC_NAME
1027
1028 /* Return a Scheme representation of the foreign value at LOC of type
1029 TYPE. When RETURN_VALUE_P is true, LOC is assumed to point to a
1030 return value buffer; otherwise LOC is assumed to point to an
1031 argument buffer. */
1032 static SCM
1033 pack (const ffi_type * type, const void *loc, int return_value_p)
1034 {
1035 switch (type->type)
1036 {
1037 case FFI_TYPE_VOID:
1038 return SCM_UNSPECIFIED;
1039 case FFI_TYPE_FLOAT:
1040 return scm_from_double (*(float *) loc);
1041 case FFI_TYPE_DOUBLE:
1042 return scm_from_double (*(double *) loc);
1043
1044 /* For integer return values smaller than `int', libffi stores the
1045 result in an `ffi_arg'-long buffer, of which only the
1046 significant bits must be kept---hence the pair of casts below.
1047 See <http://thread.gmane.org/gmane.comp.lib.ffi.general/406>
1048 for details. */
1049
1050 case FFI_TYPE_UINT8:
1051 if (return_value_p)
1052 return scm_from_uint8 ((scm_t_uint8) *(ffi_arg *) loc);
1053 else
1054 return scm_from_uint8 (* (scm_t_uint8 *) loc);
1055 case FFI_TYPE_SINT8:
1056 if (return_value_p)
1057 return scm_from_int8 ((scm_t_int8) *(ffi_arg *) loc);
1058 else
1059 return scm_from_int8 (* (scm_t_int8 *) loc);
1060 case FFI_TYPE_UINT16:
1061 if (return_value_p)
1062 return scm_from_uint16 ((scm_t_uint16) *(ffi_arg *) loc);
1063 else
1064 return scm_from_uint16 (* (scm_t_uint16 *) loc);
1065 case FFI_TYPE_SINT16:
1066 if (return_value_p)
1067 return scm_from_int16 ((scm_t_int16) *(ffi_arg *) loc);
1068 else
1069 return scm_from_int16 (* (scm_t_int16 *) loc);
1070 case FFI_TYPE_UINT32:
1071 if (return_value_p)
1072 return scm_from_uint32 ((scm_t_uint32) *(ffi_arg *) loc);
1073 else
1074 return scm_from_uint32 (* (scm_t_uint32 *) loc);
1075 case FFI_TYPE_SINT32:
1076 if (return_value_p)
1077 return scm_from_int32 ((scm_t_int32) *(ffi_arg *) loc);
1078 else
1079 return scm_from_int32 (* (scm_t_int32 *) loc);
1080 case FFI_TYPE_UINT64:
1081 return scm_from_uint64 (*(scm_t_uint64 *) loc);
1082 case FFI_TYPE_SINT64:
1083 return scm_from_int64 (*(scm_t_int64 *) loc);
1084
1085 case FFI_TYPE_STRUCT:
1086 {
1087 void *mem = scm_gc_malloc_pointerless (type->size, "foreign");
1088 memcpy (mem, loc, type->size);
1089 return scm_from_pointer (mem, NULL);
1090 }
1091 case FFI_TYPE_POINTER:
1092 return scm_from_pointer (*(void **) loc, NULL);
1093 default:
1094 abort ();
1095 }
1096 }
1097
1098
1099 SCM
1100 scm_i_foreign_call (SCM foreign, const SCM *argv)
1101 {
1102 /* FOREIGN is the pair that cif_to_procedure set as the 0th element of the
1103 objtable. */
1104 ffi_cif *cif;
1105 void (*func) (void);
1106 scm_t_uint8 *data;
1107 void *rvalue;
1108 void **args;
1109 unsigned i;
1110 size_t arg_size;
1111 scm_t_ptrdiff off;
1112
1113 cif = SCM_POINTER_VALUE (SCM_CAR (foreign));
1114 func = SCM_POINTER_VALUE (SCM_CDR (foreign));
1115
1116 /* Argument pointers. */
1117 args = alloca (sizeof (void *) * cif->nargs);
1118
1119 /* Compute the worst-case amount of memory needed to store all the argument
1120 values. Note: as of libffi 3.0.9 `cif->bytes' is undocumented and is zero,
1121 so it can't be used for that purpose. */
1122 for (i = 0, arg_size = 0; i < cif->nargs; i++)
1123 arg_size += cif->arg_types[i]->size + cif->arg_types[i]->alignment - 1;
1124
1125 /* Space for argument values, followed by return value. */
1126 data = alloca (arg_size + cif->rtype->size
1127 + max (sizeof (void *), cif->rtype->alignment));
1128
1129 /* Unpack ARGV to native values, setting ARGV pointers. */
1130 for (i = 0, off = 0;
1131 i < cif->nargs;
1132 off = (scm_t_uint8 *) args[i] - data + cif->arg_types[i]->size,
1133 i++)
1134 {
1135 /* Suitably align the storage area for argument I. */
1136 args[i] = (void *) ROUND_UP ((scm_t_uintptr) data + off,
1137 cif->arg_types[i]->alignment);
1138 assert ((scm_t_uintptr) args[i] % cif->arg_types[i]->alignment == 0);
1139 unpack (cif->arg_types[i], args[i], argv[i], 0);
1140 }
1141
1142 /* Prepare space for the return value. On some platforms, such as
1143 `armv5tel-*-linux-gnueabi', the return value has to be at least
1144 word-aligned, even if its type doesn't have any alignment requirement as is
1145 the case with `char'. */
1146 rvalue = (void *) ROUND_UP ((scm_t_uintptr) data + off,
1147 max (sizeof (void *), cif->rtype->alignment));
1148
1149 /* off we go! */
1150 ffi_call (cif, func, rvalue, args);
1151
1152 return pack (cif->rtype, rvalue, 1);
1153 }
1154
1155 \f
1156 /* Function pointers aka. "callbacks" or "closures". */
1157
1158 #ifdef FFI_CLOSURES
1159
1160 /* Trampoline to invoke a libffi closure that wraps a Scheme
1161 procedure. */
1162 static void
1163 invoke_closure (ffi_cif *cif, void *ret, void **args, void *data)
1164 {
1165 size_t i;
1166 SCM proc, *argv, result;
1167
1168 proc = PTR2SCM (data);
1169
1170 argv = alloca (cif->nargs * sizeof (*argv));
1171
1172 /* Pack ARGS to SCM values, setting ARGV pointers. */
1173 for (i = 0; i < cif->nargs; i++)
1174 argv[i] = pack (cif->arg_types[i], args[i], 0);
1175
1176 result = scm_call_n (proc, argv, cif->nargs);
1177
1178 unpack (cif->rtype, ret, result, 1);
1179 }
1180
1181 SCM_DEFINE (scm_procedure_to_pointer, "procedure->pointer", 3, 0, 0,
1182 (SCM return_type, SCM proc, SCM arg_types),
1183 "Return a pointer to a C function of type @var{return_type}\n"
1184 "taking arguments of types @var{arg_types} (a list) and\n"
1185 "behaving as a proxy to procedure @var{proc}. Thus\n"
1186 "@var{proc}'s arity, supported argument types, and return\n"
1187 "type should match @var{return_type} and @var{arg_types}.\n")
1188 #define FUNC_NAME s_scm_procedure_to_pointer
1189 {
1190 SCM cif_pointer, pointer;
1191 ffi_cif *cif;
1192 ffi_status err;
1193 void *closure, *executable;
1194
1195 cif = make_cif (return_type, arg_types, FUNC_NAME);
1196
1197 closure = ffi_closure_alloc (sizeof (ffi_closure), &executable);
1198 err = ffi_prep_closure_loc ((ffi_closure *) closure, cif,
1199 invoke_closure, SCM2PTR (proc),
1200 executable);
1201 if (err != FFI_OK)
1202 {
1203 ffi_closure_free (closure);
1204 SCM_MISC_ERROR ("`ffi_prep_closure_loc' failed", SCM_EOL);
1205 }
1206
1207 /* CIF points to GC-managed memory and it should remain as long as
1208 POINTER (see below) is live. Wrap it in a Scheme pointer to then
1209 hold a weak reference on it. */
1210 cif_pointer = scm_from_pointer (cif, NULL);
1211
1212 if (closure == executable)
1213 {
1214 pointer = scm_from_pointer (executable, ffi_closure_free);
1215 register_weak_reference (pointer,
1216 scm_list_2 (proc, cif_pointer));
1217 }
1218 else
1219 {
1220 /* CLOSURE needs to be freed eventually. However, since
1221 `GC_all_interior_pointers' is disabled, we can't just register
1222 a finalizer for CLOSURE. Instead, we create a pointer object
1223 for CLOSURE, with a finalizer, and register it as a weak
1224 reference of POINTER. */
1225 SCM friend;
1226
1227 pointer = scm_from_pointer (executable, NULL);
1228 friend = scm_from_pointer (closure, ffi_closure_free);
1229
1230 register_weak_reference (pointer,
1231 scm_list_3 (proc, cif_pointer, friend));
1232 }
1233
1234 return pointer;
1235 }
1236 #undef FUNC_NAME
1237
1238 #endif /* FFI_CLOSURES */
1239
1240 \f
1241
1242 static void
1243 scm_init_foreign (void)
1244 {
1245 #ifndef SCM_MAGIC_SNARFER
1246 #include "libguile/foreign.x"
1247 #endif
1248 scm_define (sym_void, scm_from_uint8 (SCM_FOREIGN_TYPE_VOID));
1249 scm_define (sym_float, scm_from_uint8 (SCM_FOREIGN_TYPE_FLOAT));
1250 scm_define (sym_double, scm_from_uint8 (SCM_FOREIGN_TYPE_DOUBLE));
1251 scm_define (sym_uint8, scm_from_uint8 (SCM_FOREIGN_TYPE_UINT8));
1252 scm_define (sym_int8, scm_from_uint8 (SCM_FOREIGN_TYPE_INT8));
1253 scm_define (sym_uint16, scm_from_uint8 (SCM_FOREIGN_TYPE_UINT16));
1254 scm_define (sym_int16, scm_from_uint8 (SCM_FOREIGN_TYPE_INT16));
1255 scm_define (sym_uint32, scm_from_uint8 (SCM_FOREIGN_TYPE_UINT32));
1256 scm_define (sym_int32, scm_from_uint8 (SCM_FOREIGN_TYPE_INT32));
1257 scm_define (sym_uint64, scm_from_uint8 (SCM_FOREIGN_TYPE_UINT64));
1258 scm_define (sym_int64, scm_from_uint8 (SCM_FOREIGN_TYPE_INT64));
1259
1260 scm_define (sym_short,
1261 #if SIZEOF_SHORT == 8
1262 scm_from_uint8 (SCM_FOREIGN_TYPE_INT64)
1263 #elif SIZEOF_SHORT == 4
1264 scm_from_uint8 (SCM_FOREIGN_TYPE_INT32)
1265 #elif SIZEOF_SHORT == 2
1266 scm_from_uint8 (SCM_FOREIGN_TYPE_INT16)
1267 #else
1268 # error unsupported sizeof (short)
1269 #endif
1270 );
1271
1272 scm_define (sym_unsigned_short,
1273 #if SIZEOF_SHORT == 8
1274 scm_from_uint8 (SCM_FOREIGN_TYPE_UINT64)
1275 #elif SIZEOF_SHORT == 4
1276 scm_from_uint8 (SCM_FOREIGN_TYPE_UINT32)
1277 #elif SIZEOF_SHORT == 2
1278 scm_from_uint8 (SCM_FOREIGN_TYPE_UINT16)
1279 #else
1280 # error unsupported sizeof (short)
1281 #endif
1282 );
1283
1284 scm_define (sym_int,
1285 #if SIZEOF_INT == 8
1286 scm_from_uint8 (SCM_FOREIGN_TYPE_INT64)
1287 #elif SIZEOF_INT == 4
1288 scm_from_uint8 (SCM_FOREIGN_TYPE_INT32)
1289 #else
1290 # error unsupported sizeof (int)
1291 #endif
1292 );
1293
1294 scm_define (sym_unsigned_int,
1295 #if SIZEOF_UNSIGNED_INT == 8
1296 scm_from_uint8 (SCM_FOREIGN_TYPE_UINT64)
1297 #elif SIZEOF_UNSIGNED_INT == 4
1298 scm_from_uint8 (SCM_FOREIGN_TYPE_UINT32)
1299 #else
1300 # error unsupported sizeof (unsigned int)
1301 #endif
1302 );
1303
1304 scm_define (sym_long,
1305 #if SIZEOF_LONG == 8
1306 scm_from_uint8 (SCM_FOREIGN_TYPE_INT64)
1307 #elif SIZEOF_LONG == 4
1308 scm_from_uint8 (SCM_FOREIGN_TYPE_INT32)
1309 #else
1310 # error unsupported sizeof (long)
1311 #endif
1312 );
1313
1314 scm_define (sym_unsigned_long,
1315 #if SIZEOF_UNSIGNED_LONG == 8
1316 scm_from_uint8 (SCM_FOREIGN_TYPE_UINT64)
1317 #elif SIZEOF_UNSIGNED_LONG == 4
1318 scm_from_uint8 (SCM_FOREIGN_TYPE_UINT32)
1319 #else
1320 # error unsupported sizeof (unsigned long)
1321 #endif
1322 );
1323
1324 scm_define (sym_size_t,
1325 #if SIZEOF_SIZE_T == 8
1326 scm_from_uint8 (SCM_FOREIGN_TYPE_UINT64)
1327 #elif SIZEOF_SIZE_T == 4
1328 scm_from_uint8 (SCM_FOREIGN_TYPE_UINT32)
1329 #else
1330 # error unsupported sizeof (size_t)
1331 #endif
1332 );
1333
1334 scm_define (sym_ssize_t,
1335 #if SIZEOF_SIZE_T == 8
1336 scm_from_uint8 (SCM_FOREIGN_TYPE_INT64)
1337 #elif SIZEOF_SIZE_T == 4
1338 scm_from_uint8 (SCM_FOREIGN_TYPE_INT32)
1339 #else
1340 # error unsupported sizeof (ssize_t)
1341 #endif
1342 );
1343
1344 scm_define (sym_ptrdiff_t,
1345 #if SCM_SIZEOF_SCM_T_PTRDIFF == 8
1346 scm_from_uint8 (SCM_FOREIGN_TYPE_INT64)
1347 #elif SCM_SIZEOF_SCM_T_PTRDIFF == 4
1348 scm_from_uint8 (SCM_FOREIGN_TYPE_INT32)
1349 #else
1350 # error unsupported sizeof (scm_t_ptrdiff)
1351 #endif
1352 );
1353
1354 null_pointer = scm_cell (scm_tc7_pointer, 0);
1355 scm_define (sym_null, null_pointer);
1356 }
1357
1358 void
1359 scm_register_foreign (void)
1360 {
1361 scm_c_register_extension ("libguile-" SCM_EFFECTIVE_VERSION,
1362 "scm_init_foreign",
1363 (scm_t_extension_init_func)scm_init_foreign,
1364 NULL);
1365 pointer_weak_refs = scm_make_weak_key_hash_table (SCM_UNDEFINED);
1366 }
1367
1368 /*
1369 Local Variables:
1370 c-file-style: "gnu"
1371 End:
1372 */