Print the faulty object upon invalid-keyword errors.
[bpt/guile.git] / libguile / foreign.c
CommitLineData
3a3bea72 1/* Copyright (C) 2010, 2011, 2012, 2013 Free Software Foundation, Inc.
5b46a8c2 2 *
e2c2a699
AW
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
d8b04f04
AW
23#include <ffi.h>
24
cdd47ec7 25#include <alloca.h>
d8b04f04 26#include <alignof.h>
e2c2a699 27#include <string.h>
86425e26
LC
28#include <assert.h>
29
ea7d717b 30#include "libguile/_scm.h"
20aafae2 31#include "libguile/bytevectors.h"
d8b04f04 32#include "libguile/instructions.h"
05e74813 33#include "libguile/threads.h"
ea7d717b 34#include "libguile/foreign.h"
e2c2a699
AW
35
36\f
37
ab4779ff
AW
38SCM_SYMBOL (sym_void, "void");
39SCM_SYMBOL (sym_float, "float");
40SCM_SYMBOL (sym_double, "double");
41SCM_SYMBOL (sym_uint8, "uint8");
42SCM_SYMBOL (sym_int8, "int8");
43SCM_SYMBOL (sym_uint16, "uint16");
44SCM_SYMBOL (sym_int16, "int16");
45SCM_SYMBOL (sym_uint32, "uint32");
46SCM_SYMBOL (sym_int32, "int32");
47SCM_SYMBOL (sym_uint64, "uint64");
48SCM_SYMBOL (sym_int64, "int64");
42f7c01e 49SCM_SYMBOL (sym_short, "short");
dd1464bf
LC
50SCM_SYMBOL (sym_int, "int");
51SCM_SYMBOL (sym_long, "long");
42f7c01e 52SCM_SYMBOL (sym_unsigned_short, "unsigned-short");
dd1464bf
LC
53SCM_SYMBOL (sym_unsigned_int, "unsigned-int");
54SCM_SYMBOL (sym_unsigned_long, "unsigned-long");
55SCM_SYMBOL (sym_size_t, "size_t");
3a3bea72
MW
56SCM_SYMBOL (sym_ssize_t, "ssize_t");
57SCM_SYMBOL (sym_ptrdiff_t, "ptrdiff_t");
ab4779ff 58
3435f3c0
AW
59/* that's for pointers, you know. */
60SCM_SYMBOL (sym_asterisk, "*");
61
54eb59cf 62SCM_SYMBOL (sym_null, "%null-pointer");
01ad5a7b 63SCM_SYMBOL (sym_null_pointer_error, "null-pointer-error");
54eb59cf
LC
64
65/* The cell representing the null pointer. */
3e5ea35c 66static SCM null_pointer;
3435f3c0 67
d4149a51
LC
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
01ad5a7b
LC
79/* Raise a null pointer dereference error. */
80static void
81null_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
d8b04f04
AW
88static SCM cif_to_procedure (SCM cif, SCM func_ptr);
89
90
5b46a8c2 91static SCM pointer_weak_refs = SCM_BOOL_F;
05e74813
AW
92static scm_i_pthread_mutex_t weak_refs_lock = SCM_I_PTHREAD_MUTEX_INITIALIZER;
93
20aafae2
AW
94
95static void
96register_weak_reference (SCM from, SCM to)
97{
05e74813 98 scm_i_pthread_mutex_lock (&weak_refs_lock);
5b46a8c2 99 scm_hashq_set_x (pointer_weak_refs, from, to);
05e74813 100 scm_i_pthread_mutex_unlock (&weak_refs_lock);
20aafae2 101}
d4149a51 102
e2c2a699 103static void
6922d92f 104pointer_finalizer_trampoline (void *ptr, void *data)
e2c2a699 105{
5b46a8c2
LC
106 scm_t_pointer_finalizer finalizer = data;
107 finalizer (SCM_POINTER_VALUE (PTR2SCM (ptr)));
e2c2a699
AW
108}
109
6e097560
LC
110SCM_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
d4149a51
LC
120SCM_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;
d4149a51
LC
130
131 c_address = scm_to_uintptr (address);
132 if (SCM_UNBNDP (finalizer))
133 c_finalizer = NULL;
134 else
135 {
5b46a8c2
LC
136 SCM_VALIDATE_POINTER (2, finalizer);
137 c_finalizer = SCM_POINTER_VALUE (finalizer);
d4149a51
LC
138 }
139
854aa906 140 return scm_from_pointer ((void *) c_address, c_finalizer);
d4149a51
LC
141}
142#undef FUNC_NAME
143
1d00abb0
MW
144void *
145scm_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
e2c2a699 153SCM
5b46a8c2 154scm_from_pointer (void *ptr, scm_t_pointer_finalizer finalizer)
e2c2a699 155{
9fdee5b4 156 SCM ret;
d4149a51 157
854aa906
LC
158 if (ptr == NULL && finalizer == NULL)
159 ret = null_pointer;
160 else
e2c2a699 161 {
690a0112 162 ret = scm_cell (scm_tc7_pointer, (scm_t_bits) ptr);
854aa906
LC
163
164 if (finalizer)
75ba64d6
AW
165 scm_i_set_finalizer (SCM2PTR (ret), pointer_finalizer_trampoline,
166 finalizer);
e2c2a699
AW
167 }
168
9fdee5b4 169 return ret;
e2c2a699
AW
170}
171
5b46a8c2
LC
172SCM_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
e2c2a699 176{
5b46a8c2 177 SCM_VALIDATE_POINTER (1, pointer);
01ad5a7b 178
5b46a8c2 179 return scm_from_uintptr ((scm_t_uintptr) SCM_POINTER_VALUE (pointer));
e2c2a699
AW
180}
181#undef FUNC_NAME
182
148c3317
AW
183SCM_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
195SCM_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
5b46a8c2
LC
211SCM_DEFINE (scm_pointer_to_bytevector, "pointer->bytevector", 2, 2, 0,
212 (SCM pointer, SCM len, SCM offset, SCM uvec_type),
183a2a22
LC
213 "Return a bytevector aliasing the @var{len} bytes pointed\n"
214 "to by @var{pointer}.\n\n"
20aafae2
AW
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"
183a2a22
LC
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.")
5b46a8c2 224#define FUNC_NAME s_scm_pointer_to_bytevector
20aafae2
AW
225{
226 SCM ret;
227 scm_t_int8 *ptr;
228 size_t boffset, blen;
229 scm_t_array_element_type btype;
230
5b46a8c2
LC
231 SCM_VALIDATE_POINTER (1, pointer);
232 ptr = SCM_POINTER_VALUE (pointer);
54eb59cf
LC
233
234 if (SCM_UNLIKELY (ptr == NULL))
01ad5a7b 235 null_pointer_error (FUNC_NAME);
54eb59cf 236
20aafae2
AW
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 }
d4149a51 267
20aafae2
AW
268 if (SCM_UNBNDP (offset))
269 boffset = 0;
20aafae2
AW
270 else
271 boffset = scm_to_size_t (offset);
272
d4149a51 273 blen = scm_to_size_t (len);
20aafae2 274
1acb290f
LC
275 ret = scm_c_take_typed_bytevector ((signed char *) ptr + boffset,
276 blen, btype);
5b46a8c2 277 register_weak_reference (ret, pointer);
20aafae2
AW
278 return ret;
279}
280#undef FUNC_NAME
281
22697acb
LC
282SCM_DEFINE (scm_bytevector_to_pointer, "bytevector->pointer", 1, 1, 0,
283 (SCM bv, SCM offset),
5b46a8c2 284 "Return a pointer pointer aliasing the memory pointed to by\n"
22697acb
LC
285 "@var{bv} or @var{offset} bytes after @var{bv} when @var{offset}\n"
286 "is passed.")
5b46a8c2 287#define FUNC_NAME s_scm_bytevector_to_pointer
20aafae2
AW
288{
289 SCM ret;
1acb290f 290 signed char *ptr;
22697acb 291 size_t boffset;
20aafae2
AW
292
293 SCM_VALIDATE_BYTEVECTOR (1, bv);
294 ptr = SCM_BYTEVECTOR_CONTENTS (bv);
22697acb 295
20aafae2
AW
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
5b46a8c2 302 ret = scm_from_pointer (ptr + boffset, NULL);
20aafae2
AW
303 register_weak_reference (ret, bv);
304 return ret;
305}
306#undef FUNC_NAME
307
5b46a8c2
LC
308SCM_DEFINE (scm_set_pointer_finalizer_x, "set-pointer-finalizer!", 2, 0, 0,
309 (SCM pointer, SCM finalizer),
3435f3c0 310 "Arrange for the C procedure wrapped by @var{finalizer} to be\n"
5b46a8c2 311 "called on the pointer wrapped by @var{pointer} when @var{pointer}\n"
3435f3c0
AW
312 "becomes unreachable. Note: the C procedure should not call into\n"
313 "Scheme. If you need a Scheme finalizer, use guardians.")
5b46a8c2 314#define FUNC_NAME s_scm_set_pointer_finalizer_x
3435f3c0 315{
5b46a8c2
LC
316 SCM_VALIDATE_POINTER (1, pointer);
317 SCM_VALIDATE_POINTER (2, finalizer);
d4149a51 318
75ba64d6
AW
319 scm_i_add_finalizer (SCM2PTR (pointer), pointer_finalizer_trampoline,
320 SCM_POINTER_VALUE (finalizer));
3435f3c0
AW
321
322 return SCM_UNSPECIFIED;
323}
324#undef FUNC_NAME
325
e2c2a699 326void
5b46a8c2 327scm_i_pointer_print (SCM pointer, SCM port, scm_print_state *pstate)
e2c2a699 328{
e5f7f675
AW
329 scm_puts ("#<pointer 0x", port);
330 scm_uintprint (scm_to_uintptr (scm_pointer_address (pointer)), 16, port);
e2c2a699
AW
331 scm_putc ('>', port);
332}
333
334\f
fa2a89a6
LC
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
339SCM_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
c6b08d21
AW
351SCM_DEFINE (scm_string_to_pointer, "string->pointer", 1, 1, 0,
352 (SCM string, SCM encoding),
fa2a89a6 353 "Return a foreign pointer to a nul-terminated copy of\n"
c6b08d21
AW
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}.")
fa2a89a6
LC
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
c6b08d21
AW
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,
b22e94db 380 scm_i_default_port_conversion_handler ()),
c6b08d21
AW
381 free);
382
383 scm_dynwind_end ();
384
385 return ret;
386 }
fa2a89a6
LC
387}
388#undef FUNC_NAME
389
c6b08d21
AW
390SCM_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}.")
fa2a89a6
LC
399#define FUNC_NAME s_scm_pointer_to_string
400{
c6b08d21
AW
401 size_t len;
402
fa2a89a6
LC
403 SCM_VALIDATE_POINTER (1, pointer);
404
c6b08d21
AW
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,
b22e94db 425 scm_i_default_port_conversion_handler ());
c6b08d21
AW
426
427 scm_dynwind_end ();
428
429 return ret;
430 }
fa2a89a6
LC
431}
432#undef FUNC_NAME
433
434\f
e2c2a699 435
b9264dc5
AW
436SCM_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.")
9a396cbd
AW
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:
1002c774 450 return scm_from_size_t (alignof_type (float));
9a396cbd 451 case SCM_FOREIGN_TYPE_DOUBLE:
1002c774 452 return scm_from_size_t (alignof_type (double));
9a396cbd 453 case SCM_FOREIGN_TYPE_UINT8:
1002c774 454 return scm_from_size_t (alignof_type (scm_t_uint8));
9a396cbd 455 case SCM_FOREIGN_TYPE_INT8:
1002c774 456 return scm_from_size_t (alignof_type (scm_t_int8));
9a396cbd 457 case SCM_FOREIGN_TYPE_UINT16:
1002c774 458 return scm_from_size_t (alignof_type (scm_t_uint16));
9a396cbd 459 case SCM_FOREIGN_TYPE_INT16:
1002c774 460 return scm_from_size_t (alignof_type (scm_t_int16));
9a396cbd 461 case SCM_FOREIGN_TYPE_UINT32:
1002c774 462 return scm_from_size_t (alignof_type (scm_t_uint32));
9a396cbd 463 case SCM_FOREIGN_TYPE_INT32:
1002c774 464 return scm_from_size_t (alignof_type (scm_t_int32));
9a396cbd 465 case SCM_FOREIGN_TYPE_UINT64:
1002c774 466 return scm_from_size_t (alignof_type (scm_t_uint64));
9a396cbd 467 case SCM_FOREIGN_TYPE_INT64:
1002c774 468 return scm_from_size_t (alignof_type (scm_t_int64));
9a396cbd
AW
469 default:
470 scm_wrong_type_arg (FUNC_NAME, 1, type);
471 }
472 }
3435f3c0
AW
473 else if (scm_is_eq (type, sym_asterisk))
474 /* a pointer */
1002c774 475 return scm_from_size_t (alignof_type (void*));
9a396cbd 476 else if (scm_is_pair (type))
d82f8518
LC
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 }
9a396cbd
AW
495 else
496 scm_wrong_type_arg (FUNC_NAME, 1, type);
497}
498#undef FUNC_NAME
499
b9264dc5
AW
500SCM_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.")
9a396cbd
AW
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 }
3435f3c0
AW
537 else if (scm_is_eq (type, sym_asterisk))
538 /* a pointer */
539 return scm_from_size_t (sizeof (void*));
9a396cbd
AW
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
d8b04f04
AW
558/* return 1 on success, 0 on failure */
559static int
560parse_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 }
3435f3c0
AW
572 else if (scm_is_eq (type, sym_asterisk))
573 /* a pointer */
574 return 1;
d8b04f04
AW
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
594static void
595fill_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:
2ee07358 636 scm_wrong_type_arg_msg ("pointer->procedure", 0, type,
75383ddb 637 "foreign type");
d8b04f04
AW
638 }
639 }
3435f3c0
AW
640 else if (scm_is_eq (type, sym_asterisk))
641 /* a pointer */
642 {
643 *ftype = ffi_type_pointer;
644 return;
645 }
d8b04f04
AW
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 {
9a396cbd
AW
660 ftype->elements[i] = *types;
661 *types += 1;
d8b04f04
AW
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}
33186356
LC
669
670/* Return a "cif" (call interface) for the given RETURN_TYPE and
671 ARG_TYPES. */
672static ffi_cif *
673make_cif (SCM return_type, SCM arg_types, const char *caller)
674#define FUNC_NAME caller
d8b04f04 675{
33186356 676 SCM walk;
d8b04f04
AW
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;
5b46a8c2 683
d8b04f04
AW
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));
33186356 697
d8b04f04
AW
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) */
1002c774 703 cif_len = (ROUND_UP (cif_len, alignof_type (void *))
33186356
LC
704 + (nargs + n_structs + n_struct_elts)*sizeof(void*));
705
d8b04f04
AW
706 /* then the ffi_type structs themselves, one per arg and struct element, and
707 one for the return val */
1002c774 708 cif_len = (ROUND_UP (cif_len, alignof_type (ffi_type))
33186356 709 + (nargs + n_struct_elts + 1)*sizeof(ffi_type));
087aa6aa
LC
710
711 mem = scm_gc_malloc_pointerless (cif_len, "foreign");
3ef6650d
AW
712 /* ensure all the memory is initialized, even the holes */
713 memset (mem, 0, cif_len);
087aa6aa
LC
714 cif = (ffi_cif *) mem;
715
d8b04f04 716 /* reuse cif_len to walk through the mem */
1002c774 717 cif_len = ROUND_UP (sizeof (ffi_cif), alignof_type (void *));
d8b04f04
AW
718 type_ptrs = (ffi_type**)(mem + cif_len);
719 cif_len = ROUND_UP (cif_len
33186356 720 + (nargs + n_structs + n_struct_elts)*sizeof(void*),
1002c774 721 alignof_type (ffi_type));
d8b04f04 722 types = (ffi_type*)(mem + cif_len);
33186356 723
d8b04f04
AW
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;
33186356 740
d8b04f04 741 if (FFI_OK != ffi_prep_cif (cif, FFI_DEFAULT_ABI, cif->nargs, cif->rtype,
33186356
LC
742 cif->arg_types))
743 SCM_MISC_ERROR ("ffi_prep_cif failed", SCM_EOL);
744
745 return cif;
746}
747#undef FUNC_NAME
748
2ee07358 749SCM_DEFINE (scm_pointer_to_procedure, "pointer->procedure", 3, 0, 0,
33186356
LC
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.")
2ee07358 758#define FUNC_NAME s_scm_pointer_to_procedure
33186356
LC
759{
760 ffi_cif *cif;
761
762 SCM_VALIDATE_POINTER (2, func_ptr);
d8b04f04 763
33186356
LC
764 cif = make_cif (return_type, arg_types, FUNC_NAME);
765
766 return cif_to_procedure (scm_from_pointer (cif, NULL), func_ptr);
d8b04f04
AW
767}
768#undef FUNC_NAME
769
770\f
771
772/* Pre-generate trampolines for less than 10 arguments. */
773
774#ifdef WORDS_BIGENDIAN
5ccc3764
MW
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)
d8b04f04 777#else
5ccc3764
MW
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)
d8b04f04
AW
780#endif
781
5ccc3764
MW
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) \
d8b04f04
AW
804 /* 32 */
805
5ccc3764
MW
806#define M_STATIC(x) (x)
807#define CODE(nreq) GEN_CODE (M_STATIC, nreq)
808
d8b04f04
AW
809static 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
5ccc3764
MW
822static SCM
823make_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
d8b04f04 841#undef META
5ccc3764
MW
842#undef M_STATIC
843#undef CODE
d8b04f04
AW
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 \
f9654187 860 SCM_PACK (SCM_MAKE_OBJCODE_TAG (SCM_OBJCODE_TYPE_STATIC, 0))
d8b04f04
AW
861
862static 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
893static 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
5ccc3764
MW
906static SCM large_objcode_trampolines = SCM_UNDEFINED;
907static scm_i_pthread_mutex_t large_objcode_trampolines_mutex =
908 SCM_I_PTHREAD_MUTEX_INITIALIZER;
909
d8b04f04 910static SCM
5ccc3764 911get_objcode_trampoline (unsigned int nargs)
d8b04f04 912{
5ccc3764 913 SCM objcode;
d4149a51 914
d8b04f04
AW
915 if (nargs < 10)
916 objcode = objcode_trampolines[nargs];
5ccc3764
MW
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 }
d8b04f04 928 else
5ccc3764 929 scm_misc_error ("make-foreign-function", "args >= 128 currently unimplemented",
75383ddb 930 SCM_EOL);
5ccc3764
MW
931
932 return objcode;
933}
934
935static SCM
936cif_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);
d8b04f04
AW
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
165a8643 952/* Set *LOC to the foreign representation of X with TYPE. */
4d9130a5 953static void
a6ea740b 954unpack (const ffi_type *type, void *loc, SCM x, int return_value_p)
9970cf67 955#define FUNC_NAME "scm_i_foreign_call"
4d9130a5
AW
956{
957 switch (type->type)
958 {
959 case FFI_TYPE_FLOAT:
165a8643 960 *(float *) loc = scm_to_double (x);
4d9130a5
AW
961 break;
962 case FFI_TYPE_DOUBLE:
165a8643 963 *(double *) loc = scm_to_double (x);
4d9130a5 964 break;
a6ea740b
AS
965
966 /* For integer return values smaller than `int', libffi expects the
967 result in an `ffi_arg'-long buffer. */
968
4d9130a5 969 case FFI_TYPE_UINT8:
a6ea740b
AS
970 if (return_value_p)
971 *(ffi_arg *) loc = scm_to_uint8 (x);
972 else
973 *(scm_t_uint8 *) loc = scm_to_uint8 (x);
4d9130a5
AW
974 break;
975 case FFI_TYPE_SINT8:
a6ea740b
AS
976 if (return_value_p)
977 *(ffi_arg *) loc = scm_to_int8 (x);
978 else
979 *(scm_t_int8 *) loc = scm_to_int8 (x);
4d9130a5
AW
980 break;
981 case FFI_TYPE_UINT16:
a6ea740b
AS
982 if (return_value_p)
983 *(ffi_arg *) loc = scm_to_uint16 (x);
984 else
985 *(scm_t_uint16 *) loc = scm_to_uint16 (x);
4d9130a5
AW
986 break;
987 case FFI_TYPE_SINT16:
a6ea740b
AS
988 if (return_value_p)
989 *(ffi_arg *) loc = scm_to_int16 (x);
990 else
991 *(scm_t_int16 *) loc = scm_to_int16 (x);
4d9130a5
AW
992 break;
993 case FFI_TYPE_UINT32:
a6ea740b
AS
994 if (return_value_p)
995 *(ffi_arg *) loc = scm_to_uint32 (x);
996 else
997 *(scm_t_uint32 *) loc = scm_to_uint32 (x);
4d9130a5
AW
998 break;
999 case FFI_TYPE_SINT32:
a6ea740b
AS
1000 if (return_value_p)
1001 *(ffi_arg *) loc = scm_to_int32 (x);
1002 else
1003 *(scm_t_int32 *) loc = scm_to_int32 (x);
4d9130a5
AW
1004 break;
1005 case FFI_TYPE_UINT64:
165a8643 1006 *(scm_t_uint64 *) loc = scm_to_uint64 (x);
4d9130a5
AW
1007 break;
1008 case FFI_TYPE_SINT64:
165a8643 1009 *(scm_t_int64 *) loc = scm_to_int64 (x);
4d9130a5
AW
1010 break;
1011 case FFI_TYPE_STRUCT:
9970cf67 1012 SCM_VALIDATE_POINTER (1, x);
5b46a8c2 1013 memcpy (loc, SCM_POINTER_VALUE (x), type->size);
4d9130a5
AW
1014 break;
1015 case FFI_TYPE_POINTER:
9970cf67 1016 SCM_VALIDATE_POINTER (1, x);
5b46a8c2 1017 *(void **) loc = SCM_POINTER_VALUE (x);
4d9130a5 1018 break;
443f25dc
LC
1019 case FFI_TYPE_VOID:
1020 /* Do nothing. */
1021 break;
4d9130a5
AW
1022 default:
1023 abort ();
1024 }
1025}
9970cf67 1026#undef FUNC_NAME
4d9130a5 1027
012062a0
LC
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. */
4d9130a5 1032static SCM
012062a0 1033pack (const ffi_type * type, const void *loc, int return_value_p)
4d9130a5
AW
1034{
1035 switch (type->type)
1036 {
1037 case FFI_TYPE_VOID:
1038 return SCM_UNSPECIFIED;
1039 case FFI_TYPE_FLOAT:
165a8643 1040 return scm_from_double (*(float *) loc);
4d9130a5 1041 case FFI_TYPE_DOUBLE:
165a8643 1042 return scm_from_double (*(double *) loc);
012062a0
LC
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
4d9130a5 1050 case FFI_TYPE_UINT8:
012062a0
LC
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);
4d9130a5 1055 case FFI_TYPE_SINT8:
012062a0
LC
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);
4d9130a5 1060 case FFI_TYPE_UINT16:
012062a0
LC
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);
4d9130a5 1065 case FFI_TYPE_SINT16:
012062a0
LC
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);
4d9130a5 1070 case FFI_TYPE_UINT32:
012062a0
LC
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);
4d9130a5 1075 case FFI_TYPE_SINT32:
012062a0
LC
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);
4d9130a5 1080 case FFI_TYPE_UINT64:
165a8643 1081 return scm_from_uint64 (*(scm_t_uint64 *) loc);
4d9130a5 1082 case FFI_TYPE_SINT64:
165a8643 1083 return scm_from_int64 (*(scm_t_int64 *) loc);
012062a0 1084
4d9130a5
AW
1085 case FFI_TYPE_STRUCT:
1086 {
165a8643
LC
1087 void *mem = scm_gc_malloc_pointerless (type->size, "foreign");
1088 memcpy (mem, loc, type->size);
5b46a8c2 1089 return scm_from_pointer (mem, NULL);
4d9130a5
AW
1090 }
1091 case FFI_TYPE_POINTER:
5b46a8c2 1092 return scm_from_pointer (*(void **) loc, NULL);
4d9130a5
AW
1093 default:
1094 abort ();
1095 }
1096}
1097
165a8643 1098
4d9130a5 1099SCM
165a8643 1100scm_i_foreign_call (SCM foreign, const SCM *argv)
4d9130a5
AW
1101{
1102 /* FOREIGN is the pair that cif_to_procedure set as the 0th element of the
1103 objtable. */
1104 ffi_cif *cif;
b577bc90 1105 void (*func) (void);
4d9130a5
AW
1106 scm_t_uint8 *data;
1107 void *rvalue;
1108 void **args;
1109 unsigned i;
a2c69049 1110 size_t arg_size;
4d9130a5
AW
1111 scm_t_ptrdiff off;
1112
5b46a8c2
LC
1113 cif = SCM_POINTER_VALUE (SCM_CAR (foreign));
1114 func = SCM_POINTER_VALUE (SCM_CDR (foreign));
a2c69049
LC
1115
1116 /* Argument pointers. */
b577bc90 1117 args = alloca (sizeof (void *) * cif->nargs);
a2c69049 1118
86425e26
LC
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;
a2c69049
LC
1124
1125 /* Space for argument values, followed by return value. */
86425e26
LC
1126 data = alloca (arg_size + cif->rtype->size
1127 + max (sizeof (void *), cif->rtype->alignment));
a2c69049 1128
165a8643
LC
1129 /* Unpack ARGV to native values, setting ARGV pointers. */
1130 for (i = 0, off = 0;
1131 i < cif->nargs;
86425e26
LC
1132 off = (scm_t_uint8 *) args[i] - data + cif->arg_types[i]->size,
1133 i++)
4d9130a5 1134 {
86425e26
LC
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);
a6ea740b 1139 unpack (cif->arg_types[i], args[i], argv[i], 0);
4d9130a5 1140 }
165a8643 1141
86425e26
LC
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));
4d9130a5
AW
1148
1149 /* off we go! */
1150 ffi_call (cif, func, rvalue, args);
1151
012062a0 1152 return pack (cif->rtype, rvalue, 1);
4d9130a5
AW
1153}
1154
d8b04f04 1155\f
33186356
LC
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. */
1162static void
1163invoke_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++)
012062a0 1174 argv[i] = pack (cif->arg_types[i], args[i], 0);
33186356
LC
1175
1176 result = scm_call_n (proc, argv, cif->nargs);
1177
a6ea740b 1178 unpack (cif->rtype, ret, result, 1);
33186356
LC
1179}
1180
1181SCM_DEFINE (scm_procedure_to_pointer, "procedure->pointer", 3, 0, 0,
1182 (SCM return_type, SCM proc, SCM arg_types),
b7e64f8b
BT
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"
33186356
LC
1185 "behaving as a proxy to procedure @var{proc}. Thus\n"
1186 "@var{proc}'s arity, supported argument types, and return\n"
b7e64f8b 1187 "type should match @var{return_type} and @var{arg_types}.\n")
33186356
LC
1188#define FUNC_NAME s_scm_procedure_to_pointer
1189{
46d80cae 1190 SCM cif_pointer, pointer;
33186356
LC
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
46d80cae
LC
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
33186356 1212 if (closure == executable)
46d80cae
LC
1213 {
1214 pointer = scm_from_pointer (executable, ffi_closure_free);
59a02733
LC
1215 register_weak_reference (pointer,
1216 scm_list_2 (proc, cif_pointer));
46d80cae 1217 }
33186356
LC
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
59a02733
LC
1230 register_weak_reference (pointer,
1231 scm_list_3 (proc, cif_pointer, friend));
33186356
LC
1232 }
1233
1234 return pointer;
1235}
1236#undef FUNC_NAME
1237
1238#endif /* FFI_CLOSURES */
1239
1240\f
d8b04f04 1241
ab4779ff 1242static void
e2c2a699
AW
1243scm_init_foreign (void)
1244{
1245#ifndef SCM_MAGIC_SNARFER
1246#include "libguile/foreign.x"
1247#endif
ab4779ff
AW
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));
dd1464bf 1259
42f7c01e
LC
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
dd1464bf
LC
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)
3a3bea72
MW
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)
dd1464bf
LC
1351#endif
1352 );
54eb59cf 1353
5b46a8c2 1354 null_pointer = scm_cell (scm_tc7_pointer, 0);
3e5ea35c 1355 scm_define (sym_null, null_pointer);
ab4779ff
AW
1356}
1357
1358void
1359scm_register_foreign (void)
1360{
44602b08
AW
1361 scm_c_register_extension ("libguile-" SCM_EFFECTIVE_VERSION,
1362 "scm_init_foreign",
ab4779ff
AW
1363 (scm_t_extension_init_func)scm_init_foreign,
1364 NULL);
5b46a8c2 1365 pointer_weak_refs = scm_make_weak_key_hash_table (SCM_UNDEFINED);
e2c2a699
AW
1366}
1367
1368/*
1369 Local Variables:
1370 c-file-style: "gnu"
1371 End:
1372*/