Import unbound variable reports in the VM.
[bpt/guile.git] / libguile / foreign.c
CommitLineData
e2c2a699
AW
1/* Copyright (C) 2010 Free Software Foundation, Inc.
2 *
3 * This library is free software; you can redistribute it and/or
4 * modify it under the terms of the GNU Lesser General Public License
5 * as published by the Free Software Foundation; either version 3 of
6 * the License, or (at your option) any later version.
7 *
8 * This library is distributed in the hope that it will be useful, but
9 * WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11 * Lesser General Public License for more details.
12 *
13 * You should have received a copy of the GNU Lesser General Public
14 * License along with this library; if not, write to the Free Software
15 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
16 * 02110-1301 USA
17 */
18
19#if HAVE_CONFIG_H
20# include <config.h>
21#endif
22
d8b04f04
AW
23#include <ffi.h>
24
25#include <alignof.h>
e2c2a699 26#include <string.h>
86425e26
LC
27#include <assert.h>
28
ea7d717b 29#include "libguile/_scm.h"
20aafae2 30#include "libguile/bytevectors.h"
d8b04f04 31#include "libguile/instructions.h"
ea7d717b 32#include "libguile/foreign.h"
e2c2a699
AW
33
34\f
35
ab4779ff
AW
36SCM_SYMBOL (sym_void, "void");
37SCM_SYMBOL (sym_float, "float");
38SCM_SYMBOL (sym_double, "double");
39SCM_SYMBOL (sym_uint8, "uint8");
40SCM_SYMBOL (sym_int8, "int8");
41SCM_SYMBOL (sym_uint16, "uint16");
42SCM_SYMBOL (sym_int16, "int16");
43SCM_SYMBOL (sym_uint32, "uint32");
44SCM_SYMBOL (sym_int32, "int32");
45SCM_SYMBOL (sym_uint64, "uint64");
46SCM_SYMBOL (sym_int64, "int64");
dd1464bf
LC
47SCM_SYMBOL (sym_int, "int");
48SCM_SYMBOL (sym_long, "long");
49SCM_SYMBOL (sym_unsigned_int, "unsigned-int");
50SCM_SYMBOL (sym_unsigned_long, "unsigned-long");
51SCM_SYMBOL (sym_size_t, "size_t");
ab4779ff 52
3435f3c0
AW
53/* that's for pointers, you know. */
54SCM_SYMBOL (sym_asterisk, "*");
55
54eb59cf 56SCM_SYMBOL (sym_null, "%null-pointer");
01ad5a7b 57SCM_SYMBOL (sym_null_pointer_error, "null-pointer-error");
54eb59cf
LC
58
59/* The cell representing the null pointer. */
3e5ea35c 60static SCM null_pointer;
3435f3c0 61
01ad5a7b
LC
62/* Raise a null pointer dereference error. */
63static void
64null_pointer_error (const char *func_name)
65{
66 scm_error (sym_null_pointer_error, func_name,
67 "null pointer dereference", SCM_EOL, SCM_EOL);
68}
69
70\f
d8b04f04
AW
71static SCM cif_to_procedure (SCM cif, SCM func_ptr);
72
73
20aafae2
AW
74static SCM foreign_weak_refs = SCM_BOOL_F;
75
76static void
77register_weak_reference (SCM from, SCM to)
78{
79 scm_hashq_set_x (foreign_weak_refs, from, to);
80}
81
e2c2a699
AW
82static void
83foreign_finalizer_trampoline (GC_PTR ptr, GC_PTR data)
84{
85 scm_t_foreign_finalizer finalizer = data;
52fd9639 86 finalizer (SCM_FOREIGN_POINTER (PTR2SCM (ptr), void));
e2c2a699
AW
87}
88
89SCM
52fd9639
AW
90scm_take_foreign_pointer (scm_t_foreign_type type, void *ptr, size_t len,
91 scm_t_foreign_finalizer finalizer)
e2c2a699 92{
9fdee5b4 93 SCM ret;
52fd9639 94 scm_t_bits word0;
e2c2a699 95
52fd9639
AW
96 word0 = (scm_t_bits)(scm_tc7_foreign | (type<<8)
97 | (finalizer ? (1<<16) : 0) | (len<<17));
d8b04f04 98 if (SCM_UNLIKELY ((word0 >> 17) != len))
52fd9639 99 scm_out_of_range ("scm_take_foreign_pointer", scm_from_size_t (len));
e2c2a699 100
4551e860 101 ret = scm_cell (word0, (scm_t_bits) ptr);
e2c2a699
AW
102 if (finalizer)
103 {
104 /* Register a finalizer for the newly created instance. */
105 GC_finalization_proc prev_finalizer;
106 GC_PTR prev_finalizer_data;
9fdee5b4 107 GC_REGISTER_FINALIZER_NO_ORDER (SCM2PTR (ret),
e2c2a699
AW
108 foreign_finalizer_trampoline,
109 finalizer,
110 &prev_finalizer,
111 &prev_finalizer_data);
112 }
113
9fdee5b4 114 return ret;
e2c2a699
AW
115}
116
20aafae2
AW
117SCM_DEFINE (scm_foreign_ref, "foreign-ref", 1, 0, 0,
118 (SCM foreign),
b9264dc5 119 "Reference the foreign value pointed to by @var{foreign}.\n\n"
20aafae2 120 "The value will be referenced according to its type.")
e2c2a699
AW
121#define FUNC_NAME s_scm_foreign_ref
122{
52fd9639
AW
123 scm_t_foreign_type ftype;
124 scm_t_uint8 *ptr;
e2c2a699 125
52fd9639
AW
126 SCM_VALIDATE_FOREIGN (1, foreign);
127 ptr = SCM_FOREIGN_POINTER (foreign, scm_t_uint8);
52fd9639 128 ftype = SCM_FOREIGN_TYPE (foreign);
52fd9639
AW
129
130 /* FIXME: is there a window in which we can see ptr but not foreign? */
20aafae2 131 /* FIXME: accessing unaligned pointers */
52fd9639 132 switch (ftype)
e2c2a699 133 {
20aafae2
AW
134 case SCM_FOREIGN_TYPE_VOID:
135 return scm_from_ulong ((unsigned long)ptr);
e2c2a699 136 case SCM_FOREIGN_TYPE_FLOAT:
52fd9639 137 return scm_from_double (*(float*)ptr);
e2c2a699 138 case SCM_FOREIGN_TYPE_DOUBLE:
52fd9639 139 return scm_from_double (*(double*)ptr);
e2c2a699 140 case SCM_FOREIGN_TYPE_UINT8:
52fd9639 141 return scm_from_uint8 (*(scm_t_uint8*)ptr);
e2c2a699 142 case SCM_FOREIGN_TYPE_INT8:
52fd9639 143 return scm_from_int8 (*(scm_t_int8*)ptr);
e2c2a699 144 case SCM_FOREIGN_TYPE_UINT16:
52fd9639 145 return scm_from_uint16 (*(scm_t_uint16*)ptr);
e2c2a699 146 case SCM_FOREIGN_TYPE_INT16:
52fd9639 147 return scm_from_int16 (*(scm_t_int16*)ptr);
e2c2a699 148 case SCM_FOREIGN_TYPE_UINT32:
52fd9639 149 return scm_from_uint32 (*(scm_t_uint32*)ptr);
e2c2a699 150 case SCM_FOREIGN_TYPE_INT32:
52fd9639 151 return scm_from_int32 (*(scm_t_int32*)ptr);
e2c2a699 152 case SCM_FOREIGN_TYPE_UINT64:
52fd9639 153 return scm_from_uint64 (*(scm_t_uint64*)ptr);
e2c2a699 154 case SCM_FOREIGN_TYPE_INT64:
52fd9639 155 return scm_from_int64 (*(scm_t_int64*)ptr);
e2c2a699 156 default:
75383ddb 157 scm_wrong_type_arg_msg (FUNC_NAME, 1, foreign, "foreign");
e2c2a699
AW
158 }
159}
160#undef FUNC_NAME
161
20aafae2
AW
162SCM_DEFINE (scm_foreign_set_x, "foreign-set!", 2, 0, 0,
163 (SCM foreign, SCM val),
b9264dc5 164 "Set the foreign value pointed to by @var{foreign}.\n\n"
20aafae2 165 "The value will be set according to its type.")
e2c2a699
AW
166#define FUNC_NAME s_scm_foreign_set_x
167{
52fd9639
AW
168 scm_t_foreign_type ftype;
169 scm_t_uint8 *ptr;
e2c2a699 170
52fd9639 171 SCM_VALIDATE_FOREIGN (1, foreign);
01ad5a7b 172
3e5ea35c 173 if (SCM_UNLIKELY (scm_is_eq (foreign, null_pointer)))
01ad5a7b
LC
174 /* Attempting to modify the pointer value of NULL_POINTER (which is
175 read-only anyway), so raise an error. */
176 null_pointer_error (FUNC_NAME);
177
52fd9639 178 ptr = SCM_FOREIGN_POINTER (foreign, scm_t_uint8);
52fd9639 179 ftype = SCM_FOREIGN_TYPE (foreign);
20aafae2 180
52fd9639 181 /* FIXME: is there a window in which we can see ptr but not foreign? */
20aafae2 182 /* FIXME: unaligned access */
52fd9639 183 switch (ftype)
e2c2a699 184 {
20aafae2
AW
185 case SCM_FOREIGN_TYPE_VOID:
186 SCM_SET_CELL_WORD_1 (foreign, scm_to_ulong (val));
187 break;
e2c2a699 188 case SCM_FOREIGN_TYPE_FLOAT:
52fd9639 189 *(float*)ptr = scm_to_double (val);
e2c2a699
AW
190 break;
191 case SCM_FOREIGN_TYPE_DOUBLE:
52fd9639 192 *(double*)ptr = scm_to_double (val);
e2c2a699
AW
193 break;
194 case SCM_FOREIGN_TYPE_UINT8:
52fd9639 195 *(scm_t_uint8*)ptr = scm_to_uint8 (val);
e2c2a699
AW
196 break;
197 case SCM_FOREIGN_TYPE_INT8:
52fd9639 198 *(scm_t_int8*)ptr = scm_to_int8 (val);
e2c2a699
AW
199 break;
200 case SCM_FOREIGN_TYPE_UINT16:
52fd9639 201 *(scm_t_uint16*)ptr = scm_to_uint16 (val);
e2c2a699
AW
202 break;
203 case SCM_FOREIGN_TYPE_INT16:
52fd9639 204 *(scm_t_int16*)ptr = scm_to_int16 (val);
e2c2a699
AW
205 break;
206 case SCM_FOREIGN_TYPE_UINT32:
52fd9639 207 *(scm_t_uint32*)ptr = scm_to_uint32 (val);
e2c2a699
AW
208 break;
209 case SCM_FOREIGN_TYPE_INT32:
52fd9639 210 *(scm_t_int32*)ptr = scm_to_int32 (val);
e2c2a699
AW
211 break;
212 case SCM_FOREIGN_TYPE_UINT64:
52fd9639 213 *(scm_t_uint64*)ptr = scm_to_uint64 (val);
e2c2a699
AW
214 break;
215 case SCM_FOREIGN_TYPE_INT64:
52fd9639 216 *(scm_t_int64*)ptr = scm_to_int64 (val);
e2c2a699 217 break;
e2c2a699 218 default:
75383ddb 219 scm_wrong_type_arg_msg (FUNC_NAME, 1, val, "foreign");
e2c2a699 220 }
52fd9639 221
e2c2a699
AW
222 return SCM_UNSPECIFIED;
223}
224#undef FUNC_NAME
225
20aafae2
AW
226SCM_DEFINE (scm_foreign_to_bytevector, "foreign->bytevector", 1, 3, 0,
227 (SCM foreign, SCM uvec_type, SCM offset, SCM len),
228 "Return a bytevector aliasing the memory pointed to by\n"
229 "@var{foreign}.\n\n"
230 "@var{foreign} must be a void pointer, a foreign whose type is\n"
231 "@var{void}. By default, the resulting bytevector will alias\n"
232 "all of the memory pointed to by @var{foreign}, from beginning\n"
233 "to end, treated as a @code{vu8} array.\n\n"
234 "The user may specify an alternate default interpretation for\n"
235 "the memory by passing the @var{uvec_type} argument, to indicate\n"
236 "that the memory is an array of elements of that type.\n"
237 "@var{uvec_type} should be something that\n"
238 "@code{uniform-vector-element-type} would return, like @code{f32}\n"
239 "or @code{s16}.\n\n"
240 "Users may also specify that the bytevector should only alias a\n"
241 "subset of the memory, by specifying @var{offset} and @var{len}\n"
242 "arguments.")
243#define FUNC_NAME s_scm_foreign_to_bytevector
244{
245 SCM ret;
246 scm_t_int8 *ptr;
247 size_t boffset, blen;
248 scm_t_array_element_type btype;
249
250 SCM_VALIDATE_FOREIGN_TYPED (1, foreign, VOID);
251 ptr = SCM_FOREIGN_POINTER (foreign, scm_t_int8);
54eb59cf
LC
252
253 if (SCM_UNLIKELY (ptr == NULL))
01ad5a7b 254 null_pointer_error (FUNC_NAME);
54eb59cf 255
20aafae2
AW
256 if (SCM_UNBNDP (uvec_type))
257 btype = SCM_ARRAY_ELEMENT_TYPE_VU8;
258 else
259 {
260 int i;
261 for (i = 0; i <= SCM_ARRAY_ELEMENT_TYPE_LAST; i++)
262 if (scm_is_eq (uvec_type, scm_i_array_element_types[i]))
263 break;
264 switch (i)
265 {
266 case SCM_ARRAY_ELEMENT_TYPE_VU8:
267 case SCM_ARRAY_ELEMENT_TYPE_U8:
268 case SCM_ARRAY_ELEMENT_TYPE_S8:
269 case SCM_ARRAY_ELEMENT_TYPE_U16:
270 case SCM_ARRAY_ELEMENT_TYPE_S16:
271 case SCM_ARRAY_ELEMENT_TYPE_U32:
272 case SCM_ARRAY_ELEMENT_TYPE_S32:
273 case SCM_ARRAY_ELEMENT_TYPE_U64:
274 case SCM_ARRAY_ELEMENT_TYPE_S64:
275 case SCM_ARRAY_ELEMENT_TYPE_F32:
276 case SCM_ARRAY_ELEMENT_TYPE_F64:
277 case SCM_ARRAY_ELEMENT_TYPE_C32:
278 case SCM_ARRAY_ELEMENT_TYPE_C64:
279 btype = i;
280 break;
281 default:
282 scm_wrong_type_arg_msg (FUNC_NAME, SCM_ARG1, uvec_type,
283 "uniform vector type");
284 }
285 }
286
287 if (SCM_UNBNDP (offset))
288 boffset = 0;
289 else if (SCM_FOREIGN_LEN (foreign))
290 boffset = scm_to_unsigned_integer (offset, 0,
291 SCM_FOREIGN_LEN (foreign) - 1);
292 else
293 boffset = scm_to_size_t (offset);
294
295 if (SCM_UNBNDP (len))
296 {
297 if (SCM_FOREIGN_LEN (foreign))
298 blen = SCM_FOREIGN_LEN (foreign) - boffset;
299 else
300 scm_misc_error (FUNC_NAME,
301 "length needed to convert foreign pointer to bytevector",
302 SCM_EOL);
303 }
304 else
305 {
306 if (SCM_FOREIGN_LEN (foreign))
307 blen = scm_to_unsigned_integer (len, 0,
308 SCM_FOREIGN_LEN (foreign) - boffset);
309 else
310 blen = scm_to_size_t (len);
311 }
312
313 ret = scm_c_take_typed_bytevector (ptr + boffset, blen, btype);
314 register_weak_reference (ret, foreign);
315 return ret;
316}
317#undef FUNC_NAME
318
319SCM_DEFINE (scm_bytevector_to_foreign, "bytevector->foreign", 1, 2, 0,
320 (SCM bv, SCM offset, SCM len),
321 "Return a foreign pointer aliasing the memory pointed to by\n"
322 "@var{bv}.\n\n"
323 "The resulting foreign will be a void pointer, a foreign whose\n"
324 "type is @code{void}. By default it will alias all of the\n"
325 "memory pointed to by @var{bv}, from beginning to end.\n\n"
326 "Users may explicily specify that the foreign should only alias a\n"
327 "subset of the memory, by specifying @var{offset} and @var{len}\n"
328 "arguments.")
329#define FUNC_NAME s_scm_bytevector_to_foreign
330{
331 SCM ret;
332 scm_t_int8 *ptr;
333 size_t boffset, blen;
334
335 SCM_VALIDATE_BYTEVECTOR (1, bv);
336 ptr = SCM_BYTEVECTOR_CONTENTS (bv);
337
338 if (SCM_UNBNDP (offset))
339 boffset = 0;
340 else
341 boffset = scm_to_unsigned_integer (offset, 0,
342 SCM_BYTEVECTOR_LENGTH (bv) - 1);
343
344 if (SCM_UNBNDP (len))
345 blen = SCM_BYTEVECTOR_LENGTH (bv) - boffset;
346 else
347 blen = scm_to_unsigned_integer (len, 0,
348 SCM_BYTEVECTOR_LENGTH (bv) - boffset);
349
350 ret = scm_take_foreign_pointer (SCM_FOREIGN_TYPE_VOID, ptr + boffset, blen,
351 NULL);
352 register_weak_reference (ret, bv);
353 return ret;
354}
355#undef FUNC_NAME
356
3435f3c0
AW
357SCM_DEFINE (scm_foreign_set_finalizer_x, "foreign-set-finalizer!", 2, 0, 0,
358 (SCM foreign, SCM finalizer),
359 "Arrange for the C procedure wrapped by @var{finalizer} to be\n"
360 "called on the pointer wrapped by @var{foreign} when @var{foreign}\n"
361 "becomes unreachable. Note: the C procedure should not call into\n"
362 "Scheme. If you need a Scheme finalizer, use guardians.")
363#define FUNC_NAME s_scm_foreign_set_finalizer_x
364{
365 void *c_finalizer;
366 GC_finalization_proc prev_finalizer;
367 GC_PTR prev_finalizer_data;
368
369 SCM_VALIDATE_FOREIGN_TYPED (1, foreign, VOID);
370 SCM_VALIDATE_FOREIGN_TYPED (2, finalizer, VOID);
371
372 c_finalizer = SCM_FOREIGN_POINTER (finalizer, void);
373
374 SCM_SET_CELL_WORD_0 (foreign, SCM_CELL_WORD_0 (foreign) | (1<<16));
375
376 GC_REGISTER_FINALIZER_NO_ORDER (SCM2PTR (foreign),
377 foreign_finalizer_trampoline,
378 c_finalizer,
379 &prev_finalizer,
380 &prev_finalizer_data);
381
382 return SCM_UNSPECIFIED;
383}
384#undef FUNC_NAME
385
386\f
387
e2c2a699
AW
388void
389scm_i_foreign_print (SCM foreign, SCM port, scm_print_state *pstate)
390{
391 scm_puts ("#<foreign ", port);
392 switch (SCM_FOREIGN_TYPE (foreign))
393 {
e2c2a699
AW
394 case SCM_FOREIGN_TYPE_FLOAT:
395 scm_puts ("float ", port);
e2c2a699
AW
396 break;
397 case SCM_FOREIGN_TYPE_DOUBLE:
398 scm_puts ("double ", port);
e2c2a699
AW
399 break;
400 case SCM_FOREIGN_TYPE_UINT8:
401 scm_puts ("uint8 ", port);
e2c2a699
AW
402 break;
403 case SCM_FOREIGN_TYPE_INT8:
404 scm_puts ("int8 ", port);
e2c2a699
AW
405 break;
406 case SCM_FOREIGN_TYPE_UINT16:
407 scm_puts ("uint16 ", port);
e2c2a699
AW
408 break;
409 case SCM_FOREIGN_TYPE_INT16:
410 scm_puts ("int16 ", port);
e2c2a699
AW
411 break;
412 case SCM_FOREIGN_TYPE_UINT32:
413 scm_puts ("uint32 ", port);
e2c2a699
AW
414 break;
415 case SCM_FOREIGN_TYPE_INT32:
416 scm_puts ("int32 ", port);
e2c2a699
AW
417 break;
418 case SCM_FOREIGN_TYPE_UINT64:
419 scm_puts ("uint64 ", port);
e2c2a699
AW
420 break;
421 case SCM_FOREIGN_TYPE_INT64:
422 scm_puts ("int64 ", port);
e2c2a699 423 break;
52fd9639 424 case SCM_FOREIGN_TYPE_VOID:
20aafae2 425 scm_puts ("pointer ", port);
e2c2a699
AW
426 break;
427 default:
75383ddb 428 scm_wrong_type_arg_msg ("%print-foreign", 1, foreign, "foreign");
e2c2a699 429 }
20aafae2 430 scm_display (scm_foreign_ref (foreign), port);
e2c2a699
AW
431 scm_putc ('>', port);
432}
433
434\f
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:
450 return scm_from_size_t (alignof (float));
451 case SCM_FOREIGN_TYPE_DOUBLE:
452 return scm_from_size_t (alignof (double));
453 case SCM_FOREIGN_TYPE_UINT8:
454 return scm_from_size_t (alignof (scm_t_uint8));
455 case SCM_FOREIGN_TYPE_INT8:
456 return scm_from_size_t (alignof (scm_t_int8));
457 case SCM_FOREIGN_TYPE_UINT16:
458 return scm_from_size_t (alignof (scm_t_uint16));
459 case SCM_FOREIGN_TYPE_INT16:
460 return scm_from_size_t (alignof (scm_t_int16));
461 case SCM_FOREIGN_TYPE_UINT32:
462 return scm_from_size_t (alignof (scm_t_uint32));
463 case SCM_FOREIGN_TYPE_INT32:
464 return scm_from_size_t (alignof (scm_t_int32));
465 case SCM_FOREIGN_TYPE_UINT64:
466 return scm_from_size_t (alignof (scm_t_uint64));
467 case SCM_FOREIGN_TYPE_INT64:
468 return scm_from_size_t (alignof (scm_t_int64));
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 */
475 return scm_from_size_t (alignof (void*));
9a396cbd
AW
476 else if (scm_is_pair (type))
477 /* a struct, yo */
478 return scm_alignof (scm_car (type));
479 else
480 scm_wrong_type_arg (FUNC_NAME, 1, type);
481}
482#undef FUNC_NAME
483
b9264dc5
AW
484SCM_DEFINE (scm_sizeof, "sizeof", 1, 0, 0, (SCM type),
485 "Return the size of @var{type}, in bytes.\n\n"
486 "@var{type} should be a valid C type, like @code{int}.\n"
487 "Alternately @var{type} may be the symbol @code{*}, in which\n"
488 "case the size of a pointer is returned. @var{type} may also\n"
489 "be a list of types, in which case the size of a @code{struct}\n"
490 "with ABI-conventional packing is returned.")
9a396cbd
AW
491#define FUNC_NAME s_scm_sizeof
492{
493 if (SCM_I_INUMP (type))
494 {
495 switch (SCM_I_INUM (type))
496 {
497 case SCM_FOREIGN_TYPE_FLOAT:
498 return scm_from_size_t (sizeof (float));
499 case SCM_FOREIGN_TYPE_DOUBLE:
500 return scm_from_size_t (sizeof (double));
501 case SCM_FOREIGN_TYPE_UINT8:
502 return scm_from_size_t (sizeof (scm_t_uint8));
503 case SCM_FOREIGN_TYPE_INT8:
504 return scm_from_size_t (sizeof (scm_t_int8));
505 case SCM_FOREIGN_TYPE_UINT16:
506 return scm_from_size_t (sizeof (scm_t_uint16));
507 case SCM_FOREIGN_TYPE_INT16:
508 return scm_from_size_t (sizeof (scm_t_int16));
509 case SCM_FOREIGN_TYPE_UINT32:
510 return scm_from_size_t (sizeof (scm_t_uint32));
511 case SCM_FOREIGN_TYPE_INT32:
512 return scm_from_size_t (sizeof (scm_t_int32));
513 case SCM_FOREIGN_TYPE_UINT64:
514 return scm_from_size_t (sizeof (scm_t_uint64));
515 case SCM_FOREIGN_TYPE_INT64:
516 return scm_from_size_t (sizeof (scm_t_int64));
517 default:
518 scm_wrong_type_arg (FUNC_NAME, 1, type);
519 }
520 }
3435f3c0
AW
521 else if (scm_is_eq (type, sym_asterisk))
522 /* a pointer */
523 return scm_from_size_t (sizeof (void*));
9a396cbd
AW
524 else if (scm_is_pair (type))
525 {
526 /* a struct */
527 size_t off = 0;
528 while (scm_is_pair (type))
529 {
530 off = ROUND_UP (off, scm_to_size_t (scm_alignof (scm_car (type))));
531 off += scm_to_size_t (scm_sizeof (scm_car (type)));
532 type = scm_cdr (type);
533 }
534 return scm_from_size_t (off);
535 }
536 else
537 scm_wrong_type_arg (FUNC_NAME, 1, type);
538}
539#undef FUNC_NAME
540
541
d8b04f04
AW
542/* return 1 on success, 0 on failure */
543static int
544parse_ffi_type (SCM type, int return_p, long *n_structs, long *n_struct_elts)
545{
546 if (SCM_I_INUMP (type))
547 {
548 if ((SCM_I_INUM (type) < 0 )
549 || (SCM_I_INUM (type) > SCM_FOREIGN_TYPE_LAST))
550 return 0;
551 else if (SCM_I_INUM (type) == SCM_FOREIGN_TYPE_VOID && !return_p)
552 return 0;
553 else
554 return 1;
555 }
3435f3c0
AW
556 else if (scm_is_eq (type, sym_asterisk))
557 /* a pointer */
558 return 1;
d8b04f04
AW
559 else
560 {
561 long len;
562
563 len = scm_ilength (type);
564 if (len < 1)
565 return 0;
566 while (len--)
567 {
568 if (!parse_ffi_type (scm_car (type), 0, n_structs, n_struct_elts))
569 return 0;
570 (*n_struct_elts)++;
571 type = scm_cdr (type);
572 }
573 (*n_structs)++;
574 return 1;
575 }
576}
577
578static void
579fill_ffi_type (SCM type, ffi_type *ftype, ffi_type ***type_ptrs,
580 ffi_type **types)
581{
582 if (SCM_I_INUMP (type))
583 {
584 switch (SCM_I_INUM (type))
585 {
586 case SCM_FOREIGN_TYPE_FLOAT:
587 *ftype = ffi_type_float;
588 return;
589 case SCM_FOREIGN_TYPE_DOUBLE:
590 *ftype = ffi_type_double;
591 return;
592 case SCM_FOREIGN_TYPE_UINT8:
593 *ftype = ffi_type_uint8;
594 return;
595 case SCM_FOREIGN_TYPE_INT8:
596 *ftype = ffi_type_sint8;
597 return;
598 case SCM_FOREIGN_TYPE_UINT16:
599 *ftype = ffi_type_uint16;
600 return;
601 case SCM_FOREIGN_TYPE_INT16:
602 *ftype = ffi_type_sint16;
603 return;
604 case SCM_FOREIGN_TYPE_UINT32:
605 *ftype = ffi_type_uint32;
606 return;
607 case SCM_FOREIGN_TYPE_INT32:
608 *ftype = ffi_type_sint32;
609 return;
610 case SCM_FOREIGN_TYPE_UINT64:
611 *ftype = ffi_type_uint64;
612 return;
613 case SCM_FOREIGN_TYPE_INT64:
614 *ftype = ffi_type_sint64;
615 return;
616 case SCM_FOREIGN_TYPE_VOID:
617 *ftype = ffi_type_void;
618 return;
619 default:
75383ddb
AW
620 scm_wrong_type_arg_msg ("make-foreign-function", 0, type,
621 "foreign type");
d8b04f04
AW
622 }
623 }
3435f3c0
AW
624 else if (scm_is_eq (type, sym_asterisk))
625 /* a pointer */
626 {
627 *ftype = ffi_type_pointer;
628 return;
629 }
d8b04f04
AW
630 else
631 {
632 long i, len;
633
634 len = scm_ilength (type);
635
636 ftype->size = 0;
637 ftype->alignment = 0;
638 ftype->type = FFI_TYPE_STRUCT;
639 ftype->elements = *type_ptrs;
640 *type_ptrs += len + 1;
641
642 for (i = 0; i < len; i++)
643 {
9a396cbd
AW
644 ftype->elements[i] = *types;
645 *types += 1;
d8b04f04
AW
646 fill_ffi_type (scm_car (type), ftype->elements[i],
647 type_ptrs, types);
648 type = scm_cdr (type);
649 }
650 ftype->elements[i] = NULL;
651 }
652}
653
654SCM_DEFINE (scm_make_foreign_function, "make-foreign-function", 3, 0, 0,
655 (SCM return_type, SCM func_ptr, SCM arg_types),
71725997
AW
656 "Make a foreign function.\n\n"
657 "Given the foreign void pointer @var{func_ptr}, its argument and\n"
658 "return types @var{arg_types} and @var{return_type}, return a\n"
659 "procedure that will pass arguments to the foreign function\n"
660 "and return appropriate values.\n\n"
661 "@var{arg_types} should be a list of foreign types.\n"
662 "@code{return_type} should be a foreign type.")
d8b04f04
AW
663#define FUNC_NAME s_scm_make_foreign_function
664{
665 SCM walk, scm_cif;
666 long i, nargs, n_structs, n_struct_elts;
667 size_t cif_len;
668 char *mem;
669 ffi_cif *cif;
670 ffi_type **type_ptrs;
671 ffi_type *types;
672
673 SCM_VALIDATE_FOREIGN_TYPED (2, func_ptr, VOID);
674 nargs = scm_ilength (arg_types);
675 SCM_ASSERT (nargs >= 0, arg_types, 3, FUNC_NAME);
676 /* fixme: assert nargs < 1<<32 */
677 n_structs = n_struct_elts = 0;
678
679 /* For want of talloc, we're going to have to do this in two passes: first we
680 figure out how much memory is needed for all types, then we allocate the
681 cif and the types all in one block. */
682 if (!parse_ffi_type (return_type, 1, &n_structs, &n_struct_elts))
683 scm_wrong_type_arg (FUNC_NAME, 1, return_type);
684 for (walk = arg_types; scm_is_pair (walk); walk = scm_cdr (walk))
685 if (!parse_ffi_type (scm_car (walk), 0, &n_structs, &n_struct_elts))
686 scm_wrong_type_arg (FUNC_NAME, 3, scm_car (walk));
687
688 /* the memory: with space for the cif itself */
689 cif_len = sizeof (ffi_cif);
690
691 /* then ffi_type pointers: one for each arg, one for each struct
692 element, and one for each struct (for null-termination) */
693 cif_len = (ROUND_UP (cif_len, alignof(void*))
694 + (nargs + n_structs + n_struct_elts)*sizeof(void*));
695
696 /* then the ffi_type structs themselves, one per arg and struct element, and
697 one for the return val */
698 cif_len = (ROUND_UP (cif_len, alignof(ffi_type))
699 + (nargs + n_struct_elts + 1)*sizeof(ffi_type));
087aa6aa
LC
700
701 mem = scm_gc_malloc_pointerless (cif_len, "foreign");
702 scm_cif = scm_take_foreign_pointer (SCM_FOREIGN_TYPE_VOID, mem,
703 cif_len, NULL);
704 cif = (ffi_cif *) mem;
705
d8b04f04
AW
706 /* reuse cif_len to walk through the mem */
707 cif_len = ROUND_UP (sizeof (ffi_cif), alignof(void*));
708 type_ptrs = (ffi_type**)(mem + cif_len);
709 cif_len = ROUND_UP (cif_len
710 + (nargs + n_structs + n_struct_elts)*sizeof(void*),
711 alignof(ffi_type));
712 types = (ffi_type*)(mem + cif_len);
713
714 /* whew. now knit the pointers together. */
715 cif->rtype = types++;
716 fill_ffi_type (return_type, cif->rtype, &type_ptrs, &types);
717 cif->arg_types = type_ptrs;
718 type_ptrs += nargs;
719 for (walk = arg_types, i = 0; scm_is_pair (walk); walk = scm_cdr (walk), i++)
720 {
721 cif->arg_types[i] = types++;
722 fill_ffi_type (scm_car (walk), cif->arg_types[i], &type_ptrs, &types);
723 }
724
725 /* round out the cif, and we're done. */
726 cif->abi = FFI_DEFAULT_ABI;
727 cif->nargs = nargs;
728 cif->bytes = 0;
729 cif->flags = 0;
730
731 if (FFI_OK != ffi_prep_cif (cif, FFI_DEFAULT_ABI, cif->nargs, cif->rtype,
732 cif->arg_types))
733 scm_misc_error (FUNC_NAME, "ffi_prep_cif failed", SCM_EOL);
734
735 return cif_to_procedure (scm_cif, func_ptr);
736}
737#undef FUNC_NAME
738
739\f
740
741/* Pre-generate trampolines for less than 10 arguments. */
742
743#ifdef WORDS_BIGENDIAN
744#define OBJCODE_HEADER 0, 0, 0, 8, 0, 0, 0, 40
745#define META_HEADER 0, 0, 0, 32, 0, 0, 0, 0
746#else
747#define OBJCODE_HEADER 8, 0, 0, 0, 40, 0, 0, 0
748#define META_HEADER 32, 0, 0, 0, 0, 0, 0, 0
749#endif
750
751#define CODE(nreq) \
752 OBJCODE_HEADER, \
753 /* 0 */ scm_op_assert_nargs_ee, 0, nreq, /* assert number of args */ \
754 /* 3 */ scm_op_object_ref, 0, /* push the pair with the cif and the function pointer */ \
755 /* 5 */ scm_op_foreign_call, nreq, /* and call (will return value as well) */ \
756 /* 7 */ scm_op_nop, \
757 /* 8 */ META (3, 7, nreq)
758
759#define META(start, end, nreq) \
760 META_HEADER, \
761 /* 0 */ scm_op_make_eol, /* bindings */ \
762 /* 1 */ scm_op_make_eol, /* sources */ \
763 /* 2 */ scm_op_make_int8, start, scm_op_make_int8, end, /* arity: from ip N to ip N */ \
764 /* 6 */ scm_op_make_int8, nreq, /* the arity is N required args */ \
765 /* 8 */ scm_op_list, 0, 3, /* make a list of those 3 vals */ \
766 /* 11 */ scm_op_list, 0, 1, /* and the arities will be a list of that one list */ \
767 /* 14 */ scm_op_load_symbol, 0, 0, 4, 'n', 'a', 'm', 'e', /* `name' */ \
768 /* 22 */ scm_op_object_ref, 1, /* the name from the object table */ \
769 /* 24 */ scm_op_cons, /* make a pair for the properties */ \
770 /* 25 */ scm_op_list, 0, 4, /* pack bindings, sources, and arities into list */ \
771 /* 28 */ scm_op_return, /* and return */ \
772 /* 29 */ scm_op_nop, scm_op_nop, scm_op_nop \
773 /* 32 */
774
775static const struct
776{
777 scm_t_uint64 dummy; /* ensure 8-byte alignment; perhaps there's a better way */
778 const scm_t_uint8 bytes[10 * (sizeof (struct scm_objcode) + 8
779 + sizeof (struct scm_objcode) + 32)];
780} raw_bytecode = {
781 0,
782 {
783 CODE (0), CODE (1), CODE (2), CODE (3), CODE (4),
784 CODE (5), CODE (6), CODE (7), CODE (8), CODE (9)
785 }
786};
787
788#undef CODE
789#undef META
790#undef OBJCODE_HEADER
791#undef META_HEADER
792
793/*
794 (defun generate-objcode-cells (n)
795 "Generate objcode cells for up to N arguments"
796 (interactive "p")
797 (let ((i 0))
798 (while (< i n)
799 (insert
800 (format " { STATIC_OBJCODE_TAG, SCM_PACK (raw_bytecode.bytes + %d) },\n"
801 (* (+ 4 4 8 4 4 32) i)))
802 (insert " { SCM_BOOL_F, SCM_PACK (0) },\n")
803 (setq i (1+ i)))))
804*/
805#define STATIC_OBJCODE_TAG \
806 SCM_PACK (scm_tc7_objcode | (SCM_F_OBJCODE_IS_STATIC << 8))
807
808static const struct
809{
810 scm_t_uint64 dummy; /* alignment */
811 scm_t_cell cells[10 * 2]; /* 10 double cells */
812} objcode_cells = {
813 0,
814 /* C-u 1 0 M-x generate-objcode-cells RET */
815 {
816 { STATIC_OBJCODE_TAG, SCM_PACK (raw_bytecode.bytes + 0) },
817 { SCM_BOOL_F, SCM_PACK (0) },
818 { STATIC_OBJCODE_TAG, SCM_PACK (raw_bytecode.bytes + 56) },
819 { SCM_BOOL_F, SCM_PACK (0) },
820 { STATIC_OBJCODE_TAG, SCM_PACK (raw_bytecode.bytes + 112) },
821 { SCM_BOOL_F, SCM_PACK (0) },
822 { STATIC_OBJCODE_TAG, SCM_PACK (raw_bytecode.bytes + 168) },
823 { SCM_BOOL_F, SCM_PACK (0) },
824 { STATIC_OBJCODE_TAG, SCM_PACK (raw_bytecode.bytes + 224) },
825 { SCM_BOOL_F, SCM_PACK (0) },
826 { STATIC_OBJCODE_TAG, SCM_PACK (raw_bytecode.bytes + 280) },
827 { SCM_BOOL_F, SCM_PACK (0) },
828 { STATIC_OBJCODE_TAG, SCM_PACK (raw_bytecode.bytes + 336) },
829 { SCM_BOOL_F, SCM_PACK (0) },
830 { STATIC_OBJCODE_TAG, SCM_PACK (raw_bytecode.bytes + 392) },
831 { SCM_BOOL_F, SCM_PACK (0) },
832 { STATIC_OBJCODE_TAG, SCM_PACK (raw_bytecode.bytes + 448) },
833 { SCM_BOOL_F, SCM_PACK (0) },
834 { STATIC_OBJCODE_TAG, SCM_PACK (raw_bytecode.bytes + 504) },
835 { SCM_BOOL_F, SCM_PACK (0) }
836 }
837};
838
839static const SCM objcode_trampolines[10] = {
840 SCM_PACK (objcode_cells.cells+0),
841 SCM_PACK (objcode_cells.cells+2),
842 SCM_PACK (objcode_cells.cells+4),
843 SCM_PACK (objcode_cells.cells+6),
844 SCM_PACK (objcode_cells.cells+8),
845 SCM_PACK (objcode_cells.cells+10),
846 SCM_PACK (objcode_cells.cells+12),
847 SCM_PACK (objcode_cells.cells+14),
848 SCM_PACK (objcode_cells.cells+16),
849 SCM_PACK (objcode_cells.cells+18),
850};
851
852static SCM
853cif_to_procedure (SCM cif, SCM func_ptr)
854{
855 unsigned nargs = SCM_FOREIGN_POINTER (cif, ffi_cif)->nargs;
856 SCM objcode, table, ret;
857
858 if (nargs < 10)
859 objcode = objcode_trampolines[nargs];
860 else
75383ddb
AW
861 scm_misc_error ("make-foreign-function", "args >= 10 currently unimplemented",
862 SCM_EOL);
d8b04f04
AW
863
864 table = scm_c_make_vector (2, SCM_UNDEFINED);
865 SCM_SIMPLE_VECTOR_SET (table, 0, scm_cons (cif, func_ptr));
866 SCM_SIMPLE_VECTOR_SET (table, 1, SCM_BOOL_F); /* name */
867 ret = scm_make_program (objcode, table, SCM_BOOL_F);
868
869 return ret;
870}
871
165a8643 872/* Set *LOC to the foreign representation of X with TYPE. */
4d9130a5 873static void
165a8643 874unpack (const ffi_type *type, void *loc, SCM x)
4d9130a5
AW
875{
876 switch (type->type)
877 {
878 case FFI_TYPE_FLOAT:
165a8643 879 *(float *) loc = scm_to_double (x);
4d9130a5
AW
880 break;
881 case FFI_TYPE_DOUBLE:
165a8643 882 *(double *) loc = scm_to_double (x);
4d9130a5
AW
883 break;
884 case FFI_TYPE_UINT8:
165a8643 885 *(scm_t_uint8 *) loc = scm_to_uint8 (x);
4d9130a5
AW
886 break;
887 case FFI_TYPE_SINT8:
165a8643 888 *(scm_t_int8 *) loc = scm_to_int8 (x);
4d9130a5
AW
889 break;
890 case FFI_TYPE_UINT16:
165a8643 891 *(scm_t_uint16 *) loc = scm_to_uint16 (x);
4d9130a5
AW
892 break;
893 case FFI_TYPE_SINT16:
165a8643 894 *(scm_t_int16 *) loc = scm_to_int16 (x);
4d9130a5
AW
895 break;
896 case FFI_TYPE_UINT32:
165a8643 897 *(scm_t_uint32 *) loc = scm_to_uint32 (x);
4d9130a5
AW
898 break;
899 case FFI_TYPE_SINT32:
165a8643 900 *(scm_t_int32 *) loc = scm_to_int32 (x);
4d9130a5
AW
901 break;
902 case FFI_TYPE_UINT64:
165a8643 903 *(scm_t_uint64 *) loc = scm_to_uint64 (x);
4d9130a5
AW
904 break;
905 case FFI_TYPE_SINT64:
165a8643 906 *(scm_t_int64 *) loc = scm_to_int64 (x);
4d9130a5
AW
907 break;
908 case FFI_TYPE_STRUCT:
909 if (!SCM_FOREIGN_TYPED_P (x, VOID))
165a8643 910 scm_wrong_type_arg_msg ("foreign-call", 0, x, "foreign void pointer");
4d9130a5 911 if (SCM_FOREIGN_LEN (x) && SCM_FOREIGN_LEN (x) != type->size)
165a8643
LC
912 scm_wrong_type_arg_msg ("foreign-call", 0, x,
913 "foreign void pointer of correct length");
4d9130a5
AW
914 memcpy (loc, SCM_FOREIGN_POINTER (x, void), type->size);
915 break;
916 case FFI_TYPE_POINTER:
917 if (!SCM_FOREIGN_TYPED_P (x, VOID))
165a8643
LC
918 scm_wrong_type_arg_msg ("foreign-call", 0, x, "foreign void pointer");
919 *(void **) loc = SCM_FOREIGN_POINTER (x, void);
4d9130a5
AW
920 break;
921 default:
922 abort ();
923 }
924}
925
165a8643 926/* Return a Scheme representation of the foreign value at LOC of type TYPE. */
4d9130a5 927static SCM
165a8643 928pack (const ffi_type * type, const void *loc)
4d9130a5
AW
929{
930 switch (type->type)
931 {
932 case FFI_TYPE_VOID:
933 return SCM_UNSPECIFIED;
934 case FFI_TYPE_FLOAT:
165a8643 935 return scm_from_double (*(float *) loc);
4d9130a5 936 case FFI_TYPE_DOUBLE:
165a8643 937 return scm_from_double (*(double *) loc);
4d9130a5 938 case FFI_TYPE_UINT8:
165a8643 939 return scm_from_uint8 (*(scm_t_uint8 *) loc);
4d9130a5 940 case FFI_TYPE_SINT8:
165a8643 941 return scm_from_int8 (*(scm_t_int8 *) loc);
4d9130a5 942 case FFI_TYPE_UINT16:
165a8643 943 return scm_from_uint16 (*(scm_t_uint16 *) loc);
4d9130a5 944 case FFI_TYPE_SINT16:
165a8643 945 return scm_from_int16 (*(scm_t_int16 *) loc);
4d9130a5 946 case FFI_TYPE_UINT32:
165a8643 947 return scm_from_uint32 (*(scm_t_uint32 *) loc);
4d9130a5 948 case FFI_TYPE_SINT32:
165a8643 949 return scm_from_int32 (*(scm_t_int32 *) loc);
4d9130a5 950 case FFI_TYPE_UINT64:
165a8643 951 return scm_from_uint64 (*(scm_t_uint64 *) loc);
4d9130a5 952 case FFI_TYPE_SINT64:
165a8643 953 return scm_from_int64 (*(scm_t_int64 *) loc);
4d9130a5
AW
954 case FFI_TYPE_STRUCT:
955 {
165a8643
LC
956 void *mem = scm_gc_malloc_pointerless (type->size, "foreign");
957 memcpy (mem, loc, type->size);
958 return scm_take_foreign_pointer (SCM_FOREIGN_TYPE_VOID,
959 mem, type->size, NULL);
4d9130a5
AW
960 }
961 case FFI_TYPE_POINTER:
962 return scm_take_foreign_pointer (SCM_FOREIGN_TYPE_VOID,
165a8643 963 *(void **) loc, 0, NULL);
4d9130a5
AW
964 default:
965 abort ();
966 }
967}
968
165a8643 969
4d9130a5 970SCM
165a8643 971scm_i_foreign_call (SCM foreign, const SCM *argv)
4d9130a5
AW
972{
973 /* FOREIGN is the pair that cif_to_procedure set as the 0th element of the
974 objtable. */
975 ffi_cif *cif;
b577bc90 976 void (*func) (void);
4d9130a5
AW
977 scm_t_uint8 *data;
978 void *rvalue;
979 void **args;
980 unsigned i;
a2c69049 981 size_t arg_size;
4d9130a5
AW
982 scm_t_ptrdiff off;
983
165a8643
LC
984 cif = SCM_FOREIGN_POINTER (SCM_CAR (foreign), ffi_cif);
985 func = SCM_FOREIGN_POINTER (SCM_CDR (foreign), void);
a2c69049
LC
986
987 /* Argument pointers. */
b577bc90 988 args = alloca (sizeof (void *) * cif->nargs);
a2c69049 989
86425e26
LC
990 /* Compute the worst-case amount of memory needed to store all the argument
991 values. Note: as of libffi 3.0.9 `cif->bytes' is undocumented and is zero,
992 so it can't be used for that purpose. */
993 for (i = 0, arg_size = 0; i < cif->nargs; i++)
994 arg_size += cif->arg_types[i]->size + cif->arg_types[i]->alignment - 1;
a2c69049
LC
995
996 /* Space for argument values, followed by return value. */
86425e26
LC
997 data = alloca (arg_size + cif->rtype->size
998 + max (sizeof (void *), cif->rtype->alignment));
a2c69049 999
165a8643
LC
1000 /* Unpack ARGV to native values, setting ARGV pointers. */
1001 for (i = 0, off = 0;
1002 i < cif->nargs;
86425e26
LC
1003 off = (scm_t_uint8 *) args[i] - data + cif->arg_types[i]->size,
1004 i++)
4d9130a5 1005 {
86425e26
LC
1006 /* Suitably align the storage area for argument I. */
1007 args[i] = (void *) ROUND_UP ((scm_t_uintptr) data + off,
1008 cif->arg_types[i]->alignment);
1009 assert ((scm_t_uintptr) args[i] % cif->arg_types[i]->alignment == 0);
4d9130a5 1010 unpack (cif->arg_types[i], args[i], argv[i]);
4d9130a5 1011 }
165a8643 1012
86425e26
LC
1013 /* Prepare space for the return value. On some platforms, such as
1014 `armv5tel-*-linux-gnueabi', the return value has to be at least
1015 word-aligned, even if its type doesn't have any alignment requirement as is
1016 the case with `char'. */
1017 rvalue = (void *) ROUND_UP ((scm_t_uintptr) data + off,
1018 max (sizeof (void *), cif->rtype->alignment));
4d9130a5
AW
1019
1020 /* off we go! */
1021 ffi_call (cif, func, rvalue, args);
1022
1023 return pack (cif->rtype, rvalue);
1024}
1025
d8b04f04
AW
1026\f
1027
ab4779ff 1028static void
e2c2a699
AW
1029scm_init_foreign (void)
1030{
1031#ifndef SCM_MAGIC_SNARFER
1032#include "libguile/foreign.x"
1033#endif
ab4779ff
AW
1034 scm_define (sym_void, scm_from_uint8 (SCM_FOREIGN_TYPE_VOID));
1035 scm_define (sym_float, scm_from_uint8 (SCM_FOREIGN_TYPE_FLOAT));
1036 scm_define (sym_double, scm_from_uint8 (SCM_FOREIGN_TYPE_DOUBLE));
1037 scm_define (sym_uint8, scm_from_uint8 (SCM_FOREIGN_TYPE_UINT8));
1038 scm_define (sym_int8, scm_from_uint8 (SCM_FOREIGN_TYPE_INT8));
1039 scm_define (sym_uint16, scm_from_uint8 (SCM_FOREIGN_TYPE_UINT16));
1040 scm_define (sym_int16, scm_from_uint8 (SCM_FOREIGN_TYPE_INT16));
1041 scm_define (sym_uint32, scm_from_uint8 (SCM_FOREIGN_TYPE_UINT32));
1042 scm_define (sym_int32, scm_from_uint8 (SCM_FOREIGN_TYPE_INT32));
1043 scm_define (sym_uint64, scm_from_uint8 (SCM_FOREIGN_TYPE_UINT64));
1044 scm_define (sym_int64, scm_from_uint8 (SCM_FOREIGN_TYPE_INT64));
dd1464bf
LC
1045
1046 scm_define (sym_int,
1047#if SIZEOF_INT == 8
1048 scm_from_uint8 (SCM_FOREIGN_TYPE_INT64)
1049#elif SIZEOF_INT == 4
1050 scm_from_uint8 (SCM_FOREIGN_TYPE_INT32)
1051#else
1052# error unsupported sizeof (int)
1053#endif
1054 );
1055
1056 scm_define (sym_unsigned_int,
1057#if SIZEOF_UNSIGNED_INT == 8
1058 scm_from_uint8 (SCM_FOREIGN_TYPE_UINT64)
1059#elif SIZEOF_UNSIGNED_INT == 4
1060 scm_from_uint8 (SCM_FOREIGN_TYPE_UINT32)
1061#else
1062# error unsupported sizeof (unsigned int)
1063#endif
1064 );
1065
1066 scm_define (sym_long,
1067#if SIZEOF_LONG == 8
1068 scm_from_uint8 (SCM_FOREIGN_TYPE_INT64)
1069#elif SIZEOF_LONG == 4
1070 scm_from_uint8 (SCM_FOREIGN_TYPE_INT32)
1071#else
1072# error unsupported sizeof (long)
1073#endif
1074 );
1075
1076 scm_define (sym_unsigned_long,
1077#if SIZEOF_UNSIGNED_LONG == 8
1078 scm_from_uint8 (SCM_FOREIGN_TYPE_UINT64)
1079#elif SIZEOF_UNSIGNED_LONG == 4
1080 scm_from_uint8 (SCM_FOREIGN_TYPE_UINT32)
1081#else
1082# error unsupported sizeof (unsigned long)
1083#endif
1084 );
1085
1086 scm_define (sym_size_t,
1087#if SIZEOF_SIZE_T == 8
1088 scm_from_uint8 (SCM_FOREIGN_TYPE_UINT64)
1089#elif SIZEOF_SIZE_T == 4
1090 scm_from_uint8 (SCM_FOREIGN_TYPE_UINT32)
1091#else
1092# error unsupported sizeof (size_t)
1093#endif
1094 );
54eb59cf 1095
3e5ea35c
AW
1096 null_pointer = scm_cell (scm_tc7_foreign | (SCM_FOREIGN_TYPE_VOID << 8UL),
1097 0);
1098 scm_define (sym_null, null_pointer);
ab4779ff
AW
1099}
1100
1101void
1102scm_register_foreign (void)
1103{
44602b08
AW
1104 scm_c_register_extension ("libguile-" SCM_EFFECTIVE_VERSION,
1105 "scm_init_foreign",
ab4779ff
AW
1106 (scm_t_extension_init_func)scm_init_foreign,
1107 NULL);
20aafae2 1108 foreign_weak_refs = scm_make_weak_key_hash_table (SCM_UNDEFINED);
e2c2a699
AW
1109}
1110
1111/*
1112 Local Variables:
1113 c-file-style: "gnu"
1114 End:
1115*/