Avoid signed overflow and use size_t in bytevectors.c.
[bpt/guile.git] / libguile / foreign.c
CommitLineData
156119b0 1/* Copyright (C) 2010-2014 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{
b7c1b60c
MW
345 void **ptr;
346
fa2a89a6
LC
347 SCM_VALIDATE_POINTER (1, pointer);
348
b7c1b60c
MW
349 ptr = SCM_POINTER_VALUE (pointer);
350 if (SCM_UNLIKELY (ptr == NULL))
351 null_pointer_error (FUNC_NAME);
352
353 return scm_from_pointer (*ptr, NULL);
fa2a89a6
LC
354}
355#undef FUNC_NAME
356
c6b08d21
AW
357SCM_DEFINE (scm_string_to_pointer, "string->pointer", 1, 1, 0,
358 (SCM string, SCM encoding),
fa2a89a6 359 "Return a foreign pointer to a nul-terminated copy of\n"
c6b08d21
AW
360 "@var{string} in the given @var{encoding}, defaulting to\n"
361 "the current locale encoding. The C string is freed when\n"
362 "the returned foreign pointer becomes unreachable.\n\n"
363 "This is the Scheme equivalent of @code{scm_to_stringn}.")
fa2a89a6
LC
364#define FUNC_NAME s_scm_string_to_pointer
365{
366 SCM_VALIDATE_STRING (1, string);
367
368 /* XXX: Finalizers slow down libgc; they could be avoided if
369 `scm_to_string' & co. were able to use libgc-allocated memory. */
370
c6b08d21
AW
371 if (SCM_UNBNDP (encoding))
372 return scm_from_pointer (scm_to_locale_string (string), free);
373 else
374 {
375 char *enc;
376 SCM ret;
377
378 SCM_VALIDATE_STRING (2, encoding);
379
380 enc = scm_to_locale_string (encoding);
381 scm_dynwind_begin (0);
382 scm_dynwind_free (enc);
383
384 ret = scm_from_pointer
385 (scm_to_stringn (string, NULL, enc,
b22e94db 386 scm_i_default_port_conversion_handler ()),
c6b08d21
AW
387 free);
388
389 scm_dynwind_end ();
390
391 return ret;
392 }
fa2a89a6
LC
393}
394#undef FUNC_NAME
395
c6b08d21
AW
396SCM_DEFINE (scm_pointer_to_string, "pointer->string", 1, 2, 0,
397 (SCM pointer, SCM length, SCM encoding),
398 "Return the string representing the C string pointed to by\n"
399 "@var{pointer}. If @var{length} is omitted or @code{-1}, the\n"
400 "string is assumed to be nul-terminated. Otherwise\n"
401 "@var{length} is the number of bytes in memory pointed to by\n"
402 "@var{pointer}. The C string is assumed to be in the given\n"
403 "@var{encoding}, defaulting to the current locale encoding.\n\n"
404 "This is the Scheme equivalent of @code{scm_from_stringn}.")
fa2a89a6
LC
405#define FUNC_NAME s_scm_pointer_to_string
406{
c6b08d21
AW
407 size_t len;
408
fa2a89a6
LC
409 SCM_VALIDATE_POINTER (1, pointer);
410
c6b08d21
AW
411 if (SCM_UNBNDP (length)
412 || scm_is_true (scm_eqv_p (length, scm_from_int (-1))))
413 len = (size_t)-1;
414 else
415 len = scm_to_size_t (length);
416
417 if (SCM_UNBNDP (encoding))
418 return scm_from_locale_stringn (SCM_POINTER_VALUE (pointer), len);
419 else
420 {
421 char *enc;
422 SCM ret;
423
424 SCM_VALIDATE_STRING (3, encoding);
425
426 enc = scm_to_locale_string (encoding);
427 scm_dynwind_begin (0);
428 scm_dynwind_free (enc);
429
430 ret = scm_from_stringn (SCM_POINTER_VALUE (pointer), len, enc,
b22e94db 431 scm_i_default_port_conversion_handler ());
c6b08d21
AW
432
433 scm_dynwind_end ();
434
435 return ret;
436 }
fa2a89a6
LC
437}
438#undef FUNC_NAME
439
440\f
e2c2a699 441
b9264dc5
AW
442SCM_DEFINE (scm_alignof, "alignof", 1, 0, 0, (SCM type),
443 "Return the alignment of @var{type}, in bytes.\n\n"
444 "@var{type} should be a valid C type, like @code{int}.\n"
445 "Alternately @var{type} may be the symbol @code{*}, in which\n"
446 "case the alignment of a pointer is returned. @var{type} may\n"
447 "also be a list of types, in which case the alignment of a\n"
448 "@code{struct} with ABI-conventional packing is returned.")
9a396cbd
AW
449#define FUNC_NAME s_scm_alignof
450{
451 if (SCM_I_INUMP (type))
452 {
453 switch (SCM_I_INUM (type))
454 {
455 case SCM_FOREIGN_TYPE_FLOAT:
1002c774 456 return scm_from_size_t (alignof_type (float));
9a396cbd 457 case SCM_FOREIGN_TYPE_DOUBLE:
1002c774 458 return scm_from_size_t (alignof_type (double));
9a396cbd 459 case SCM_FOREIGN_TYPE_UINT8:
1002c774 460 return scm_from_size_t (alignof_type (scm_t_uint8));
9a396cbd 461 case SCM_FOREIGN_TYPE_INT8:
1002c774 462 return scm_from_size_t (alignof_type (scm_t_int8));
9a396cbd 463 case SCM_FOREIGN_TYPE_UINT16:
1002c774 464 return scm_from_size_t (alignof_type (scm_t_uint16));
9a396cbd 465 case SCM_FOREIGN_TYPE_INT16:
1002c774 466 return scm_from_size_t (alignof_type (scm_t_int16));
9a396cbd 467 case SCM_FOREIGN_TYPE_UINT32:
1002c774 468 return scm_from_size_t (alignof_type (scm_t_uint32));
9a396cbd 469 case SCM_FOREIGN_TYPE_INT32:
1002c774 470 return scm_from_size_t (alignof_type (scm_t_int32));
9a396cbd 471 case SCM_FOREIGN_TYPE_UINT64:
1002c774 472 return scm_from_size_t (alignof_type (scm_t_uint64));
9a396cbd 473 case SCM_FOREIGN_TYPE_INT64:
1002c774 474 return scm_from_size_t (alignof_type (scm_t_int64));
9a396cbd
AW
475 default:
476 scm_wrong_type_arg (FUNC_NAME, 1, type);
477 }
478 }
3435f3c0
AW
479 else if (scm_is_eq (type, sym_asterisk))
480 /* a pointer */
1002c774 481 return scm_from_size_t (alignof_type (void*));
9a396cbd 482 else if (scm_is_pair (type))
d82f8518
LC
483 {
484 /* TYPE is a structure. Section 3-3 of the i386, x86_64, PowerPC,
485 and SPARC P.S. of the System V ABI all say: "Aggregates
486 (structures and arrays) and unions assume the alignment of
487 their most strictly aligned component." */
488 size_t max;
489
490 for (max = 0; scm_is_pair (type); type = SCM_CDR (type))
491 {
492 size_t align;
493
494 align = scm_to_size_t (scm_alignof (SCM_CAR (type)));
495 if (align > max)
496 max = align;
497 }
498
499 return scm_from_size_t (max);
500 }
9a396cbd
AW
501 else
502 scm_wrong_type_arg (FUNC_NAME, 1, type);
503}
504#undef FUNC_NAME
505
b9264dc5
AW
506SCM_DEFINE (scm_sizeof, "sizeof", 1, 0, 0, (SCM type),
507 "Return the size of @var{type}, in bytes.\n\n"
508 "@var{type} should be a valid C type, like @code{int}.\n"
509 "Alternately @var{type} may be the symbol @code{*}, in which\n"
510 "case the size of a pointer is returned. @var{type} may also\n"
511 "be a list of types, in which case the size of a @code{struct}\n"
512 "with ABI-conventional packing is returned.")
9a396cbd
AW
513#define FUNC_NAME s_scm_sizeof
514{
515 if (SCM_I_INUMP (type))
516 {
517 switch (SCM_I_INUM (type))
518 {
519 case SCM_FOREIGN_TYPE_FLOAT:
520 return scm_from_size_t (sizeof (float));
521 case SCM_FOREIGN_TYPE_DOUBLE:
522 return scm_from_size_t (sizeof (double));
523 case SCM_FOREIGN_TYPE_UINT8:
524 return scm_from_size_t (sizeof (scm_t_uint8));
525 case SCM_FOREIGN_TYPE_INT8:
526 return scm_from_size_t (sizeof (scm_t_int8));
527 case SCM_FOREIGN_TYPE_UINT16:
528 return scm_from_size_t (sizeof (scm_t_uint16));
529 case SCM_FOREIGN_TYPE_INT16:
530 return scm_from_size_t (sizeof (scm_t_int16));
531 case SCM_FOREIGN_TYPE_UINT32:
532 return scm_from_size_t (sizeof (scm_t_uint32));
533 case SCM_FOREIGN_TYPE_INT32:
534 return scm_from_size_t (sizeof (scm_t_int32));
535 case SCM_FOREIGN_TYPE_UINT64:
536 return scm_from_size_t (sizeof (scm_t_uint64));
537 case SCM_FOREIGN_TYPE_INT64:
538 return scm_from_size_t (sizeof (scm_t_int64));
539 default:
540 scm_wrong_type_arg (FUNC_NAME, 1, type);
541 }
542 }
3435f3c0
AW
543 else if (scm_is_eq (type, sym_asterisk))
544 /* a pointer */
545 return scm_from_size_t (sizeof (void*));
9a396cbd
AW
546 else if (scm_is_pair (type))
547 {
548 /* a struct */
549 size_t off = 0;
550 while (scm_is_pair (type))
551 {
552 off = ROUND_UP (off, scm_to_size_t (scm_alignof (scm_car (type))));
553 off += scm_to_size_t (scm_sizeof (scm_car (type)));
554 type = scm_cdr (type);
555 }
556 return scm_from_size_t (off);
557 }
558 else
559 scm_wrong_type_arg (FUNC_NAME, 1, type);
560}
561#undef FUNC_NAME
562
563
d8b04f04
AW
564/* return 1 on success, 0 on failure */
565static int
566parse_ffi_type (SCM type, int return_p, long *n_structs, long *n_struct_elts)
567{
568 if (SCM_I_INUMP (type))
569 {
570 if ((SCM_I_INUM (type) < 0 )
571 || (SCM_I_INUM (type) > SCM_FOREIGN_TYPE_LAST))
572 return 0;
573 else if (SCM_I_INUM (type) == SCM_FOREIGN_TYPE_VOID && !return_p)
574 return 0;
575 else
576 return 1;
577 }
3435f3c0
AW
578 else if (scm_is_eq (type, sym_asterisk))
579 /* a pointer */
580 return 1;
d8b04f04
AW
581 else
582 {
583 long len;
584
585 len = scm_ilength (type);
586 if (len < 1)
587 return 0;
588 while (len--)
589 {
590 if (!parse_ffi_type (scm_car (type), 0, n_structs, n_struct_elts))
591 return 0;
592 (*n_struct_elts)++;
593 type = scm_cdr (type);
594 }
595 (*n_structs)++;
596 return 1;
597 }
598}
599
600static void
601fill_ffi_type (SCM type, ffi_type *ftype, ffi_type ***type_ptrs,
602 ffi_type **types)
603{
604 if (SCM_I_INUMP (type))
605 {
606 switch (SCM_I_INUM (type))
607 {
608 case SCM_FOREIGN_TYPE_FLOAT:
609 *ftype = ffi_type_float;
610 return;
611 case SCM_FOREIGN_TYPE_DOUBLE:
612 *ftype = ffi_type_double;
613 return;
614 case SCM_FOREIGN_TYPE_UINT8:
615 *ftype = ffi_type_uint8;
616 return;
617 case SCM_FOREIGN_TYPE_INT8:
618 *ftype = ffi_type_sint8;
619 return;
620 case SCM_FOREIGN_TYPE_UINT16:
621 *ftype = ffi_type_uint16;
622 return;
623 case SCM_FOREIGN_TYPE_INT16:
624 *ftype = ffi_type_sint16;
625 return;
626 case SCM_FOREIGN_TYPE_UINT32:
627 *ftype = ffi_type_uint32;
628 return;
629 case SCM_FOREIGN_TYPE_INT32:
630 *ftype = ffi_type_sint32;
631 return;
632 case SCM_FOREIGN_TYPE_UINT64:
633 *ftype = ffi_type_uint64;
634 return;
635 case SCM_FOREIGN_TYPE_INT64:
636 *ftype = ffi_type_sint64;
637 return;
638 case SCM_FOREIGN_TYPE_VOID:
639 *ftype = ffi_type_void;
640 return;
641 default:
2ee07358 642 scm_wrong_type_arg_msg ("pointer->procedure", 0, type,
75383ddb 643 "foreign type");
d8b04f04
AW
644 }
645 }
3435f3c0
AW
646 else if (scm_is_eq (type, sym_asterisk))
647 /* a pointer */
648 {
649 *ftype = ffi_type_pointer;
650 return;
651 }
d8b04f04
AW
652 else
653 {
654 long i, len;
655
656 len = scm_ilength (type);
657
658 ftype->size = 0;
659 ftype->alignment = 0;
660 ftype->type = FFI_TYPE_STRUCT;
661 ftype->elements = *type_ptrs;
662 *type_ptrs += len + 1;
663
664 for (i = 0; i < len; i++)
665 {
9a396cbd
AW
666 ftype->elements[i] = *types;
667 *types += 1;
d8b04f04
AW
668 fill_ffi_type (scm_car (type), ftype->elements[i],
669 type_ptrs, types);
670 type = scm_cdr (type);
671 }
672 ftype->elements[i] = NULL;
673 }
674}
33186356
LC
675
676/* Return a "cif" (call interface) for the given RETURN_TYPE and
677 ARG_TYPES. */
678static ffi_cif *
679make_cif (SCM return_type, SCM arg_types, const char *caller)
680#define FUNC_NAME caller
d8b04f04 681{
33186356 682 SCM walk;
d8b04f04
AW
683 long i, nargs, n_structs, n_struct_elts;
684 size_t cif_len;
685 char *mem;
686 ffi_cif *cif;
687 ffi_type **type_ptrs;
688 ffi_type *types;
5b46a8c2 689
d8b04f04
AW
690 nargs = scm_ilength (arg_types);
691 SCM_ASSERT (nargs >= 0, arg_types, 3, FUNC_NAME);
692 /* fixme: assert nargs < 1<<32 */
693 n_structs = n_struct_elts = 0;
694
695 /* For want of talloc, we're going to have to do this in two passes: first we
696 figure out how much memory is needed for all types, then we allocate the
697 cif and the types all in one block. */
698 if (!parse_ffi_type (return_type, 1, &n_structs, &n_struct_elts))
699 scm_wrong_type_arg (FUNC_NAME, 1, return_type);
700 for (walk = arg_types; scm_is_pair (walk); walk = scm_cdr (walk))
701 if (!parse_ffi_type (scm_car (walk), 0, &n_structs, &n_struct_elts))
702 scm_wrong_type_arg (FUNC_NAME, 3, scm_car (walk));
33186356 703
d8b04f04
AW
704 /* the memory: with space for the cif itself */
705 cif_len = sizeof (ffi_cif);
706
707 /* then ffi_type pointers: one for each arg, one for each struct
708 element, and one for each struct (for null-termination) */
1002c774 709 cif_len = (ROUND_UP (cif_len, alignof_type (void *))
33186356
LC
710 + (nargs + n_structs + n_struct_elts)*sizeof(void*));
711
d8b04f04
AW
712 /* then the ffi_type structs themselves, one per arg and struct element, and
713 one for the return val */
1002c774 714 cif_len = (ROUND_UP (cif_len, alignof_type (ffi_type))
33186356 715 + (nargs + n_struct_elts + 1)*sizeof(ffi_type));
087aa6aa
LC
716
717 mem = scm_gc_malloc_pointerless (cif_len, "foreign");
3ef6650d
AW
718 /* ensure all the memory is initialized, even the holes */
719 memset (mem, 0, cif_len);
087aa6aa
LC
720 cif = (ffi_cif *) mem;
721
d8b04f04 722 /* reuse cif_len to walk through the mem */
1002c774 723 cif_len = ROUND_UP (sizeof (ffi_cif), alignof_type (void *));
d8b04f04
AW
724 type_ptrs = (ffi_type**)(mem + cif_len);
725 cif_len = ROUND_UP (cif_len
33186356 726 + (nargs + n_structs + n_struct_elts)*sizeof(void*),
1002c774 727 alignof_type (ffi_type));
d8b04f04 728 types = (ffi_type*)(mem + cif_len);
33186356 729
d8b04f04
AW
730 /* whew. now knit the pointers together. */
731 cif->rtype = types++;
732 fill_ffi_type (return_type, cif->rtype, &type_ptrs, &types);
733 cif->arg_types = type_ptrs;
734 type_ptrs += nargs;
735 for (walk = arg_types, i = 0; scm_is_pair (walk); walk = scm_cdr (walk), i++)
736 {
737 cif->arg_types[i] = types++;
738 fill_ffi_type (scm_car (walk), cif->arg_types[i], &type_ptrs, &types);
739 }
740
741 /* round out the cif, and we're done. */
742 cif->abi = FFI_DEFAULT_ABI;
743 cif->nargs = nargs;
744 cif->bytes = 0;
745 cif->flags = 0;
33186356 746
d8b04f04 747 if (FFI_OK != ffi_prep_cif (cif, FFI_DEFAULT_ABI, cif->nargs, cif->rtype,
33186356
LC
748 cif->arg_types))
749 SCM_MISC_ERROR ("ffi_prep_cif failed", SCM_EOL);
750
751 return cif;
752}
753#undef FUNC_NAME
754
2ee07358 755SCM_DEFINE (scm_pointer_to_procedure, "pointer->procedure", 3, 0, 0,
33186356
LC
756 (SCM return_type, SCM func_ptr, SCM arg_types),
757 "Make a foreign function.\n\n"
758 "Given the foreign void pointer @var{func_ptr}, its argument and\n"
759 "return types @var{arg_types} and @var{return_type}, return a\n"
760 "procedure that will pass arguments to the foreign function\n"
761 "and return appropriate values.\n\n"
762 "@var{arg_types} should be a list of foreign types.\n"
763 "@code{return_type} should be a foreign type.")
2ee07358 764#define FUNC_NAME s_scm_pointer_to_procedure
33186356
LC
765{
766 ffi_cif *cif;
767
768 SCM_VALIDATE_POINTER (2, func_ptr);
d8b04f04 769
33186356
LC
770 cif = make_cif (return_type, arg_types, FUNC_NAME);
771
772 return cif_to_procedure (scm_from_pointer (cif, NULL), func_ptr);
d8b04f04
AW
773}
774#undef FUNC_NAME
775
776\f
777
778/* Pre-generate trampolines for less than 10 arguments. */
779
780#ifdef WORDS_BIGENDIAN
5ccc3764
MW
781#define OBJCODE_HEADER(M) M (0), M (0), M (0), M (8), M (0), M (0), M (0), M (40)
782#define META_HEADER(M) M (0), M (0), M (0), M (32), M (0), M (0), M (0), M (0)
d8b04f04 783#else
5ccc3764
MW
784#define OBJCODE_HEADER(M) M (8), M (0), M (0), M (0), M (40), M (0), M (0), M (0)
785#define META_HEADER(M) M (32), M (0), M (0), M (0), M (0), M (0), M (0), M (0)
d8b04f04
AW
786#endif
787
5ccc3764
MW
788#define GEN_CODE(M, nreq) \
789 OBJCODE_HEADER (M), \
790 /* 0 */ M (scm_op_assert_nargs_ee), M (0), M (nreq), /* assert number of args */ \
791 /* 3 */ M (scm_op_object_ref), M (0), /* push the pair with the cif and the function pointer */ \
792 /* 5 */ M (scm_op_foreign_call), M (nreq), /* and call (will return value as well) */ \
793 /* 7 */ M (scm_op_nop), \
794 /* 8 */ META (M, 3, 7, nreq)
795
796#define META(M, start, end, nreq) \
797 META_HEADER (M), \
798 /* 0 */ M (scm_op_make_eol), /* bindings */ \
799 /* 1 */ M (scm_op_make_eol), /* sources */ \
800 /* 2 */ M (scm_op_make_int8), M (start), M (scm_op_make_int8), M (end), /* arity: from ip N to ip N */ \
801 /* 6 */ M (scm_op_make_int8), M (nreq), /* the arity is N required args */ \
802 /* 8 */ M (scm_op_list), M (0), M (3), /* make a list of those 3 vals */ \
803 /* 11 */ M (scm_op_list), M (0), M (1), /* and the arities will be a list of that one list */ \
804 /* 14 */ M (scm_op_load_symbol), M (0), M (0), M (4), M ('n'), M ('a'), M ('M'), M ('e'), /* `name' */ \
805 /* 22 */ M (scm_op_object_ref), M (1), /* the name from the object table */ \
806 /* 24 */ M (scm_op_cons), /* make a pair for the properties */ \
807 /* 25 */ M (scm_op_list), M (0), M (4), /* pack bindings, sources, and arities into list */ \
808 /* 28 */ M (scm_op_return), /* and return */ \
809 /* 29 */ M (scm_op_nop), M (scm_op_nop), M (scm_op_nop) \
d8b04f04
AW
810 /* 32 */
811
5ccc3764
MW
812#define M_STATIC(x) (x)
813#define CODE(nreq) GEN_CODE (M_STATIC, nreq)
814
d8b04f04
AW
815static const struct
816{
156119b0 817 SCM_ALIGNED (8) scm_t_uint64 dummy; /* alignment */
d8b04f04
AW
818 const scm_t_uint8 bytes[10 * (sizeof (struct scm_objcode) + 8
819 + sizeof (struct scm_objcode) + 32)];
820} raw_bytecode = {
821 0,
822 {
823 CODE (0), CODE (1), CODE (2), CODE (3), CODE (4),
824 CODE (5), CODE (6), CODE (7), CODE (8), CODE (9)
825 }
826};
827
5ccc3764
MW
828static SCM
829make_objcode_trampoline (unsigned int nargs)
830{
831 const int size = sizeof (struct scm_objcode) + 8
832 + sizeof (struct scm_objcode) + 32;
833 SCM bytecode = scm_c_make_bytevector (size);
834 scm_t_uint8 *bytes = (scm_t_uint8 *) SCM_BYTEVECTOR_CONTENTS (bytecode);
835 int i = 0;
836
837#define M_DYNAMIC(x) (bytes[i++] = (x))
838 GEN_CODE (M_DYNAMIC, nargs);
839#undef M_DYNAMIC
840
841 if (i != size)
842 scm_syserror ("make_objcode_trampoline");
843 return scm_bytecode_to_native_objcode (bytecode);
844}
845
846#undef GEN_CODE
d8b04f04 847#undef META
5ccc3764
MW
848#undef M_STATIC
849#undef CODE
d8b04f04
AW
850#undef OBJCODE_HEADER
851#undef META_HEADER
852
853/*
854 (defun generate-objcode-cells (n)
855 "Generate objcode cells for up to N arguments"
856 (interactive "p")
857 (let ((i 0))
858 (while (< i n)
859 (insert
860 (format " { STATIC_OBJCODE_TAG, SCM_PACK (raw_bytecode.bytes + %d) },\n"
861 (* (+ 4 4 8 4 4 32) i)))
862 (insert " { SCM_BOOL_F, SCM_PACK (0) },\n")
863 (setq i (1+ i)))))
864*/
865#define STATIC_OBJCODE_TAG \
f9654187 866 SCM_PACK (SCM_MAKE_OBJCODE_TAG (SCM_OBJCODE_TYPE_STATIC, 0))
d8b04f04
AW
867
868static const struct
869{
156119b0 870 SCM_ALIGNED (8) scm_t_uint64 dummy; /* alignment */
d8b04f04
AW
871 scm_t_cell cells[10 * 2]; /* 10 double cells */
872} objcode_cells = {
873 0,
874 /* C-u 1 0 M-x generate-objcode-cells RET */
875 {
876 { STATIC_OBJCODE_TAG, SCM_PACK (raw_bytecode.bytes + 0) },
877 { SCM_BOOL_F, SCM_PACK (0) },
878 { STATIC_OBJCODE_TAG, SCM_PACK (raw_bytecode.bytes + 56) },
879 { SCM_BOOL_F, SCM_PACK (0) },
880 { STATIC_OBJCODE_TAG, SCM_PACK (raw_bytecode.bytes + 112) },
881 { SCM_BOOL_F, SCM_PACK (0) },
882 { STATIC_OBJCODE_TAG, SCM_PACK (raw_bytecode.bytes + 168) },
883 { SCM_BOOL_F, SCM_PACK (0) },
884 { STATIC_OBJCODE_TAG, SCM_PACK (raw_bytecode.bytes + 224) },
885 { SCM_BOOL_F, SCM_PACK (0) },
886 { STATIC_OBJCODE_TAG, SCM_PACK (raw_bytecode.bytes + 280) },
887 { SCM_BOOL_F, SCM_PACK (0) },
888 { STATIC_OBJCODE_TAG, SCM_PACK (raw_bytecode.bytes + 336) },
889 { SCM_BOOL_F, SCM_PACK (0) },
890 { STATIC_OBJCODE_TAG, SCM_PACK (raw_bytecode.bytes + 392) },
891 { SCM_BOOL_F, SCM_PACK (0) },
892 { STATIC_OBJCODE_TAG, SCM_PACK (raw_bytecode.bytes + 448) },
893 { SCM_BOOL_F, SCM_PACK (0) },
894 { STATIC_OBJCODE_TAG, SCM_PACK (raw_bytecode.bytes + 504) },
895 { SCM_BOOL_F, SCM_PACK (0) }
896 }
897};
898
899static const SCM objcode_trampolines[10] = {
900 SCM_PACK (objcode_cells.cells+0),
901 SCM_PACK (objcode_cells.cells+2),
902 SCM_PACK (objcode_cells.cells+4),
903 SCM_PACK (objcode_cells.cells+6),
904 SCM_PACK (objcode_cells.cells+8),
905 SCM_PACK (objcode_cells.cells+10),
906 SCM_PACK (objcode_cells.cells+12),
907 SCM_PACK (objcode_cells.cells+14),
908 SCM_PACK (objcode_cells.cells+16),
909 SCM_PACK (objcode_cells.cells+18),
910};
911
5ccc3764
MW
912static SCM large_objcode_trampolines = SCM_UNDEFINED;
913static scm_i_pthread_mutex_t large_objcode_trampolines_mutex =
914 SCM_I_PTHREAD_MUTEX_INITIALIZER;
915
d8b04f04 916static SCM
5ccc3764 917get_objcode_trampoline (unsigned int nargs)
d8b04f04 918{
5ccc3764 919 SCM objcode;
d4149a51 920
d8b04f04
AW
921 if (nargs < 10)
922 objcode = objcode_trampolines[nargs];
5ccc3764
MW
923 else if (nargs < 128)
924 {
925 scm_i_scm_pthread_mutex_lock (&large_objcode_trampolines_mutex);
926 if (SCM_UNBNDP (large_objcode_trampolines))
927 large_objcode_trampolines = scm_c_make_vector (128, SCM_UNDEFINED);
928 objcode = scm_c_vector_ref (large_objcode_trampolines, nargs);
929 if (SCM_UNBNDP (objcode))
930 scm_c_vector_set_x (large_objcode_trampolines, nargs,
931 objcode = make_objcode_trampoline (nargs));
932 scm_i_pthread_mutex_unlock (&large_objcode_trampolines_mutex);
933 }
d8b04f04 934 else
5ccc3764 935 scm_misc_error ("make-foreign-function", "args >= 128 currently unimplemented",
75383ddb 936 SCM_EOL);
5ccc3764
MW
937
938 return objcode;
939}
940
941static SCM
942cif_to_procedure (SCM cif, SCM func_ptr)
943{
944 ffi_cif *c_cif;
945 SCM objcode, table, ret;
946
947 c_cif = (ffi_cif *) SCM_POINTER_VALUE (cif);
948 objcode = get_objcode_trampoline (c_cif->nargs);
d8b04f04
AW
949
950 table = scm_c_make_vector (2, SCM_UNDEFINED);
951 SCM_SIMPLE_VECTOR_SET (table, 0, scm_cons (cif, func_ptr));
952 SCM_SIMPLE_VECTOR_SET (table, 1, SCM_BOOL_F); /* name */
953 ret = scm_make_program (objcode, table, SCM_BOOL_F);
954
955 return ret;
956}
957
165a8643 958/* Set *LOC to the foreign representation of X with TYPE. */
4d9130a5 959static void
a6ea740b 960unpack (const ffi_type *type, void *loc, SCM x, int return_value_p)
9970cf67 961#define FUNC_NAME "scm_i_foreign_call"
4d9130a5
AW
962{
963 switch (type->type)
964 {
965 case FFI_TYPE_FLOAT:
165a8643 966 *(float *) loc = scm_to_double (x);
4d9130a5
AW
967 break;
968 case FFI_TYPE_DOUBLE:
165a8643 969 *(double *) loc = scm_to_double (x);
4d9130a5 970 break;
a6ea740b
AS
971
972 /* For integer return values smaller than `int', libffi expects the
973 result in an `ffi_arg'-long buffer. */
974
4d9130a5 975 case FFI_TYPE_UINT8:
a6ea740b
AS
976 if (return_value_p)
977 *(ffi_arg *) loc = scm_to_uint8 (x);
978 else
979 *(scm_t_uint8 *) loc = scm_to_uint8 (x);
4d9130a5
AW
980 break;
981 case FFI_TYPE_SINT8:
a6ea740b
AS
982 if (return_value_p)
983 *(ffi_arg *) loc = scm_to_int8 (x);
984 else
985 *(scm_t_int8 *) loc = scm_to_int8 (x);
4d9130a5
AW
986 break;
987 case FFI_TYPE_UINT16:
a6ea740b
AS
988 if (return_value_p)
989 *(ffi_arg *) loc = scm_to_uint16 (x);
990 else
991 *(scm_t_uint16 *) loc = scm_to_uint16 (x);
4d9130a5
AW
992 break;
993 case FFI_TYPE_SINT16:
a6ea740b
AS
994 if (return_value_p)
995 *(ffi_arg *) loc = scm_to_int16 (x);
996 else
997 *(scm_t_int16 *) loc = scm_to_int16 (x);
4d9130a5
AW
998 break;
999 case FFI_TYPE_UINT32:
a6ea740b
AS
1000 if (return_value_p)
1001 *(ffi_arg *) loc = scm_to_uint32 (x);
1002 else
1003 *(scm_t_uint32 *) loc = scm_to_uint32 (x);
4d9130a5
AW
1004 break;
1005 case FFI_TYPE_SINT32:
a6ea740b
AS
1006 if (return_value_p)
1007 *(ffi_arg *) loc = scm_to_int32 (x);
1008 else
1009 *(scm_t_int32 *) loc = scm_to_int32 (x);
4d9130a5
AW
1010 break;
1011 case FFI_TYPE_UINT64:
165a8643 1012 *(scm_t_uint64 *) loc = scm_to_uint64 (x);
4d9130a5
AW
1013 break;
1014 case FFI_TYPE_SINT64:
165a8643 1015 *(scm_t_int64 *) loc = scm_to_int64 (x);
4d9130a5
AW
1016 break;
1017 case FFI_TYPE_STRUCT:
9970cf67 1018 SCM_VALIDATE_POINTER (1, x);
5b46a8c2 1019 memcpy (loc, SCM_POINTER_VALUE (x), type->size);
4d9130a5
AW
1020 break;
1021 case FFI_TYPE_POINTER:
9970cf67 1022 SCM_VALIDATE_POINTER (1, x);
5b46a8c2 1023 *(void **) loc = SCM_POINTER_VALUE (x);
4d9130a5 1024 break;
443f25dc
LC
1025 case FFI_TYPE_VOID:
1026 /* Do nothing. */
1027 break;
4d9130a5
AW
1028 default:
1029 abort ();
1030 }
1031}
9970cf67 1032#undef FUNC_NAME
4d9130a5 1033
012062a0
LC
1034/* Return a Scheme representation of the foreign value at LOC of type
1035 TYPE. When RETURN_VALUE_P is true, LOC is assumed to point to a
1036 return value buffer; otherwise LOC is assumed to point to an
1037 argument buffer. */
4d9130a5 1038static SCM
012062a0 1039pack (const ffi_type * type, const void *loc, int return_value_p)
4d9130a5
AW
1040{
1041 switch (type->type)
1042 {
1043 case FFI_TYPE_VOID:
1044 return SCM_UNSPECIFIED;
1045 case FFI_TYPE_FLOAT:
165a8643 1046 return scm_from_double (*(float *) loc);
4d9130a5 1047 case FFI_TYPE_DOUBLE:
165a8643 1048 return scm_from_double (*(double *) loc);
012062a0
LC
1049
1050 /* For integer return values smaller than `int', libffi stores the
1051 result in an `ffi_arg'-long buffer, of which only the
1052 significant bits must be kept---hence the pair of casts below.
1053 See <http://thread.gmane.org/gmane.comp.lib.ffi.general/406>
1054 for details. */
1055
4d9130a5 1056 case FFI_TYPE_UINT8:
012062a0
LC
1057 if (return_value_p)
1058 return scm_from_uint8 ((scm_t_uint8) *(ffi_arg *) loc);
1059 else
1060 return scm_from_uint8 (* (scm_t_uint8 *) loc);
4d9130a5 1061 case FFI_TYPE_SINT8:
012062a0
LC
1062 if (return_value_p)
1063 return scm_from_int8 ((scm_t_int8) *(ffi_arg *) loc);
1064 else
1065 return scm_from_int8 (* (scm_t_int8 *) loc);
4d9130a5 1066 case FFI_TYPE_UINT16:
012062a0
LC
1067 if (return_value_p)
1068 return scm_from_uint16 ((scm_t_uint16) *(ffi_arg *) loc);
1069 else
1070 return scm_from_uint16 (* (scm_t_uint16 *) loc);
4d9130a5 1071 case FFI_TYPE_SINT16:
012062a0
LC
1072 if (return_value_p)
1073 return scm_from_int16 ((scm_t_int16) *(ffi_arg *) loc);
1074 else
1075 return scm_from_int16 (* (scm_t_int16 *) loc);
4d9130a5 1076 case FFI_TYPE_UINT32:
012062a0
LC
1077 if (return_value_p)
1078 return scm_from_uint32 ((scm_t_uint32) *(ffi_arg *) loc);
1079 else
1080 return scm_from_uint32 (* (scm_t_uint32 *) loc);
4d9130a5 1081 case FFI_TYPE_SINT32:
012062a0
LC
1082 if (return_value_p)
1083 return scm_from_int32 ((scm_t_int32) *(ffi_arg *) loc);
1084 else
1085 return scm_from_int32 (* (scm_t_int32 *) loc);
4d9130a5 1086 case FFI_TYPE_UINT64:
165a8643 1087 return scm_from_uint64 (*(scm_t_uint64 *) loc);
4d9130a5 1088 case FFI_TYPE_SINT64:
165a8643 1089 return scm_from_int64 (*(scm_t_int64 *) loc);
012062a0 1090
4d9130a5
AW
1091 case FFI_TYPE_STRUCT:
1092 {
165a8643
LC
1093 void *mem = scm_gc_malloc_pointerless (type->size, "foreign");
1094 memcpy (mem, loc, type->size);
5b46a8c2 1095 return scm_from_pointer (mem, NULL);
4d9130a5
AW
1096 }
1097 case FFI_TYPE_POINTER:
5b46a8c2 1098 return scm_from_pointer (*(void **) loc, NULL);
4d9130a5
AW
1099 default:
1100 abort ();
1101 }
1102}
1103
165a8643 1104
4d9130a5 1105SCM
165a8643 1106scm_i_foreign_call (SCM foreign, const SCM *argv)
4d9130a5
AW
1107{
1108 /* FOREIGN is the pair that cif_to_procedure set as the 0th element of the
1109 objtable. */
1110 ffi_cif *cif;
b577bc90 1111 void (*func) (void);
4d9130a5
AW
1112 scm_t_uint8 *data;
1113 void *rvalue;
1114 void **args;
1115 unsigned i;
a2c69049 1116 size_t arg_size;
4d9130a5
AW
1117 scm_t_ptrdiff off;
1118
5b46a8c2
LC
1119 cif = SCM_POINTER_VALUE (SCM_CAR (foreign));
1120 func = SCM_POINTER_VALUE (SCM_CDR (foreign));
a2c69049
LC
1121
1122 /* Argument pointers. */
b577bc90 1123 args = alloca (sizeof (void *) * cif->nargs);
a2c69049 1124
86425e26
LC
1125 /* Compute the worst-case amount of memory needed to store all the argument
1126 values. Note: as of libffi 3.0.9 `cif->bytes' is undocumented and is zero,
1127 so it can't be used for that purpose. */
1128 for (i = 0, arg_size = 0; i < cif->nargs; i++)
1129 arg_size += cif->arg_types[i]->size + cif->arg_types[i]->alignment - 1;
a2c69049
LC
1130
1131 /* Space for argument values, followed by return value. */
86425e26
LC
1132 data = alloca (arg_size + cif->rtype->size
1133 + max (sizeof (void *), cif->rtype->alignment));
a2c69049 1134
165a8643
LC
1135 /* Unpack ARGV to native values, setting ARGV pointers. */
1136 for (i = 0, off = 0;
1137 i < cif->nargs;
86425e26
LC
1138 off = (scm_t_uint8 *) args[i] - data + cif->arg_types[i]->size,
1139 i++)
4d9130a5 1140 {
86425e26
LC
1141 /* Suitably align the storage area for argument I. */
1142 args[i] = (void *) ROUND_UP ((scm_t_uintptr) data + off,
1143 cif->arg_types[i]->alignment);
1144 assert ((scm_t_uintptr) args[i] % cif->arg_types[i]->alignment == 0);
a6ea740b 1145 unpack (cif->arg_types[i], args[i], argv[i], 0);
4d9130a5 1146 }
165a8643 1147
86425e26
LC
1148 /* Prepare space for the return value. On some platforms, such as
1149 `armv5tel-*-linux-gnueabi', the return value has to be at least
1150 word-aligned, even if its type doesn't have any alignment requirement as is
1151 the case with `char'. */
1152 rvalue = (void *) ROUND_UP ((scm_t_uintptr) data + off,
1153 max (sizeof (void *), cif->rtype->alignment));
4d9130a5
AW
1154
1155 /* off we go! */
1156 ffi_call (cif, func, rvalue, args);
1157
012062a0 1158 return pack (cif->rtype, rvalue, 1);
4d9130a5
AW
1159}
1160
d8b04f04 1161\f
33186356
LC
1162/* Function pointers aka. "callbacks" or "closures". */
1163
1164#ifdef FFI_CLOSURES
1165
1166/* Trampoline to invoke a libffi closure that wraps a Scheme
1167 procedure. */
1168static void
1169invoke_closure (ffi_cif *cif, void *ret, void **args, void *data)
1170{
1171 size_t i;
1172 SCM proc, *argv, result;
1173
1174 proc = PTR2SCM (data);
1175
1176 argv = alloca (cif->nargs * sizeof (*argv));
1177
1178 /* Pack ARGS to SCM values, setting ARGV pointers. */
1179 for (i = 0; i < cif->nargs; i++)
012062a0 1180 argv[i] = pack (cif->arg_types[i], args[i], 0);
33186356
LC
1181
1182 result = scm_call_n (proc, argv, cif->nargs);
1183
a6ea740b 1184 unpack (cif->rtype, ret, result, 1);
33186356
LC
1185}
1186
1187SCM_DEFINE (scm_procedure_to_pointer, "procedure->pointer", 3, 0, 0,
1188 (SCM return_type, SCM proc, SCM arg_types),
b7e64f8b
BT
1189 "Return a pointer to a C function of type @var{return_type}\n"
1190 "taking arguments of types @var{arg_types} (a list) and\n"
33186356
LC
1191 "behaving as a proxy to procedure @var{proc}. Thus\n"
1192 "@var{proc}'s arity, supported argument types, and return\n"
b7e64f8b 1193 "type should match @var{return_type} and @var{arg_types}.\n")
33186356
LC
1194#define FUNC_NAME s_scm_procedure_to_pointer
1195{
46d80cae 1196 SCM cif_pointer, pointer;
33186356
LC
1197 ffi_cif *cif;
1198 ffi_status err;
1199 void *closure, *executable;
1200
1201 cif = make_cif (return_type, arg_types, FUNC_NAME);
1202
1203 closure = ffi_closure_alloc (sizeof (ffi_closure), &executable);
1204 err = ffi_prep_closure_loc ((ffi_closure *) closure, cif,
1205 invoke_closure, SCM2PTR (proc),
1206 executable);
1207 if (err != FFI_OK)
1208 {
1209 ffi_closure_free (closure);
1210 SCM_MISC_ERROR ("`ffi_prep_closure_loc' failed", SCM_EOL);
1211 }
1212
46d80cae
LC
1213 /* CIF points to GC-managed memory and it should remain as long as
1214 POINTER (see below) is live. Wrap it in a Scheme pointer to then
1215 hold a weak reference on it. */
1216 cif_pointer = scm_from_pointer (cif, NULL);
1217
33186356 1218 if (closure == executable)
46d80cae
LC
1219 {
1220 pointer = scm_from_pointer (executable, ffi_closure_free);
59a02733
LC
1221 register_weak_reference (pointer,
1222 scm_list_2 (proc, cif_pointer));
46d80cae 1223 }
33186356
LC
1224 else
1225 {
1226 /* CLOSURE needs to be freed eventually. However, since
1227 `GC_all_interior_pointers' is disabled, we can't just register
1228 a finalizer for CLOSURE. Instead, we create a pointer object
1229 for CLOSURE, with a finalizer, and register it as a weak
1230 reference of POINTER. */
1231 SCM friend;
1232
1233 pointer = scm_from_pointer (executable, NULL);
1234 friend = scm_from_pointer (closure, ffi_closure_free);
1235
59a02733
LC
1236 register_weak_reference (pointer,
1237 scm_list_3 (proc, cif_pointer, friend));
33186356
LC
1238 }
1239
1240 return pointer;
1241}
1242#undef FUNC_NAME
1243
1244#endif /* FFI_CLOSURES */
1245
1246\f
d8b04f04 1247
ab4779ff 1248static void
e2c2a699
AW
1249scm_init_foreign (void)
1250{
1251#ifndef SCM_MAGIC_SNARFER
1252#include "libguile/foreign.x"
1253#endif
ab4779ff
AW
1254 scm_define (sym_void, scm_from_uint8 (SCM_FOREIGN_TYPE_VOID));
1255 scm_define (sym_float, scm_from_uint8 (SCM_FOREIGN_TYPE_FLOAT));
1256 scm_define (sym_double, scm_from_uint8 (SCM_FOREIGN_TYPE_DOUBLE));
1257 scm_define (sym_uint8, scm_from_uint8 (SCM_FOREIGN_TYPE_UINT8));
1258 scm_define (sym_int8, scm_from_uint8 (SCM_FOREIGN_TYPE_INT8));
1259 scm_define (sym_uint16, scm_from_uint8 (SCM_FOREIGN_TYPE_UINT16));
1260 scm_define (sym_int16, scm_from_uint8 (SCM_FOREIGN_TYPE_INT16));
1261 scm_define (sym_uint32, scm_from_uint8 (SCM_FOREIGN_TYPE_UINT32));
1262 scm_define (sym_int32, scm_from_uint8 (SCM_FOREIGN_TYPE_INT32));
1263 scm_define (sym_uint64, scm_from_uint8 (SCM_FOREIGN_TYPE_UINT64));
1264 scm_define (sym_int64, scm_from_uint8 (SCM_FOREIGN_TYPE_INT64));
dd1464bf 1265
42f7c01e
LC
1266 scm_define (sym_short,
1267#if SIZEOF_SHORT == 8
1268 scm_from_uint8 (SCM_FOREIGN_TYPE_INT64)
1269#elif SIZEOF_SHORT == 4
1270 scm_from_uint8 (SCM_FOREIGN_TYPE_INT32)
1271#elif SIZEOF_SHORT == 2
1272 scm_from_uint8 (SCM_FOREIGN_TYPE_INT16)
1273#else
1274# error unsupported sizeof (short)
1275#endif
1276 );
1277
1278 scm_define (sym_unsigned_short,
1279#if SIZEOF_SHORT == 8
1280 scm_from_uint8 (SCM_FOREIGN_TYPE_UINT64)
1281#elif SIZEOF_SHORT == 4
1282 scm_from_uint8 (SCM_FOREIGN_TYPE_UINT32)
1283#elif SIZEOF_SHORT == 2
1284 scm_from_uint8 (SCM_FOREIGN_TYPE_UINT16)
1285#else
1286# error unsupported sizeof (short)
1287#endif
1288 );
1289
dd1464bf
LC
1290 scm_define (sym_int,
1291#if SIZEOF_INT == 8
1292 scm_from_uint8 (SCM_FOREIGN_TYPE_INT64)
1293#elif SIZEOF_INT == 4
1294 scm_from_uint8 (SCM_FOREIGN_TYPE_INT32)
1295#else
1296# error unsupported sizeof (int)
1297#endif
1298 );
1299
1300 scm_define (sym_unsigned_int,
1301#if SIZEOF_UNSIGNED_INT == 8
1302 scm_from_uint8 (SCM_FOREIGN_TYPE_UINT64)
1303#elif SIZEOF_UNSIGNED_INT == 4
1304 scm_from_uint8 (SCM_FOREIGN_TYPE_UINT32)
1305#else
1306# error unsupported sizeof (unsigned int)
1307#endif
1308 );
1309
1310 scm_define (sym_long,
1311#if SIZEOF_LONG == 8
1312 scm_from_uint8 (SCM_FOREIGN_TYPE_INT64)
1313#elif SIZEOF_LONG == 4
1314 scm_from_uint8 (SCM_FOREIGN_TYPE_INT32)
1315#else
1316# error unsupported sizeof (long)
1317#endif
1318 );
1319
1320 scm_define (sym_unsigned_long,
1321#if SIZEOF_UNSIGNED_LONG == 8
1322 scm_from_uint8 (SCM_FOREIGN_TYPE_UINT64)
1323#elif SIZEOF_UNSIGNED_LONG == 4
1324 scm_from_uint8 (SCM_FOREIGN_TYPE_UINT32)
1325#else
1326# error unsupported sizeof (unsigned long)
1327#endif
1328 );
1329
1330 scm_define (sym_size_t,
1331#if SIZEOF_SIZE_T == 8
1332 scm_from_uint8 (SCM_FOREIGN_TYPE_UINT64)
1333#elif SIZEOF_SIZE_T == 4
1334 scm_from_uint8 (SCM_FOREIGN_TYPE_UINT32)
1335#else
1336# error unsupported sizeof (size_t)
3a3bea72
MW
1337#endif
1338 );
1339
1340 scm_define (sym_ssize_t,
1341#if SIZEOF_SIZE_T == 8
1342 scm_from_uint8 (SCM_FOREIGN_TYPE_INT64)
1343#elif SIZEOF_SIZE_T == 4
1344 scm_from_uint8 (SCM_FOREIGN_TYPE_INT32)
1345#else
1346# error unsupported sizeof (ssize_t)
1347#endif
1348 );
1349
1350 scm_define (sym_ptrdiff_t,
1351#if SCM_SIZEOF_SCM_T_PTRDIFF == 8
1352 scm_from_uint8 (SCM_FOREIGN_TYPE_INT64)
1353#elif SCM_SIZEOF_SCM_T_PTRDIFF == 4
1354 scm_from_uint8 (SCM_FOREIGN_TYPE_INT32)
1355#else
1356# error unsupported sizeof (scm_t_ptrdiff)
dd1464bf
LC
1357#endif
1358 );
54eb59cf 1359
5b46a8c2 1360 null_pointer = scm_cell (scm_tc7_pointer, 0);
3e5ea35c 1361 scm_define (sym_null, null_pointer);
ab4779ff
AW
1362}
1363
1364void
1365scm_register_foreign (void)
1366{
44602b08
AW
1367 scm_c_register_extension ("libguile-" SCM_EFFECTIVE_VERSION,
1368 "scm_init_foreign",
ab4779ff
AW
1369 (scm_t_extension_init_func)scm_init_foreign,
1370 NULL);
5b46a8c2 1371 pointer_weak_refs = scm_make_weak_key_hash_table (SCM_UNDEFINED);
e2c2a699
AW
1372}
1373
1374/*
1375 Local Variables:
1376 c-file-style: "gnu"
1377 End:
1378*/