1 /********************************************
2  ** Do not edit this file!
3  ** This file is generated from foreign.rktc,
4  ** to make changes, edit that file and
5  ** run it to generate an updated version
6  ** of this file.
7  ********************************************/
8 
9 #include "schpriv.h"
10 #include "schmach.h"
11 #include "schrktio.h"
12 
13 #ifndef DONT_USE_FOREIGN
14 
15 #include <errno.h>
16 
17 #ifdef MZ_USE_FFIPOLL
18 # define MZ_USE_FFIPOLL_COND 1
19 #else /* MZ_USE_FFIPOLL undefined */
20 # define MZ_USE_FFIPOLL_COND 0
21 #endif /* MZ_USE_FFIPOLL */
22 
23 #ifndef SIZEOF_BOOL
24 # define SIZEOF_BOOL 0
25 #endif /* SIZEOF_BOOL */
26 #if SIZEOF_BOOL != 0
27 # include <stdbool.h>
28 #endif /* SIZEOF_BOOL != 0 */
29 
30 #ifndef WINDOWS_DYNAMIC_LOAD
31 # include <dlfcn.h>
32 #else /* WINDOWS_DYNAMIC_LOAD defined */
33 # include <windows.h>
34 #endif /* WINDOWS_DYNAMIC_LOAD */
35 
36 #if !defined(WINDOWS_DYNAMIC_LOAD) || defined(__MINGW32__)
37    typedef   signed char Tsint8;
38    typedef unsigned char Tuint8;
39 
40 # if SIZEOF_SHORT == 2
41    typedef   signed short Tsint16;
42    typedef unsigned short Tuint16;
43 # elif SIZEOF_INT == 2
44    typedef   signed int Tsint16;
45    typedef unsigned int Tuint16;
46 # else
47 #  error "configuration error, please contact PLT (int16)"
48 # endif
49 
50 # if SIZEOF_INT == 4
51    typedef   signed int Tsint32;
52    typedef unsigned int Tuint32;
53 # elif SIZEOF_LONG == 4
54    typedef   signed long Tsint32;
55    typedef unsigned long Tuint32;
56 # else
57 #  error "configuration error, please contact PLT (int32)"
58 # endif
59 
60 # if SIZEOF_LONG == 8
61    typedef   signed long Tsint64;
62    typedef unsigned long Tuint64;
63 # elif SIZEOF_LONG_LONG == 8
64    typedef   signed long long Tsint64;
65    typedef unsigned long long Tuint64;
66 # else
67 #  error "configuration error, please contact PLT (int64)"
68 # endif
69 
70 #else /* !defined(WINDOWS_DYNAMIC_LOAD) || defined(__MINGW32__)  */
71 
72 # ifndef __CYGWIN32__
73 #  include <wtypes.h>
74    typedef          _int8  Tsint8;
75    typedef unsigned _int8  Tuint8;
76    typedef          _int16 Tsint16;
77    typedef unsigned _int16 Tuint16;
78    typedef          _int32 Tsint32;
79    typedef unsigned _int32 Tuint32;
80    typedef          _int64 Tsint64;
81    typedef unsigned _int64 Tuint64;
82 # endif
83 
84 #endif /* !defined(WINDOWS_DYNAMIC_LOAD) || defined(__MINGW32__) */
85 
86 #include "ffi.h"
87 
88 typedef void *(*Scheme_Malloc_Proc)(size_t);
89 static Scheme_Malloc_Proc mode_to_allocator(const char *who, Scheme_Object *mode);
90 
91 static Scheme_Object *nonatomic_sym;
92 static Scheme_Object *atomic_sym;
93 static Scheme_Object *stubborn_sym;
94 static Scheme_Object *uncollectable_sym;
95 static Scheme_Object *eternal_sym;
96 static Scheme_Object *interior_sym;
97 static Scheme_Object *atomic_interior_sym;
98 static Scheme_Object *raw_sym;
99 static Scheme_Object *tagged_sym;
100 static Scheme_Object *fail_ok_sym;
101 
102 #ifndef MZ_PRECISE_GC
103 # define XFORM_OK_PLUS +
104 # define GC_CAN_IGNORE /* empty */
105 #endif
106 
107 #define W_OFFSET(src, delta) ((char *)(src) XFORM_OK_PLUS (delta))
108 
109 /* same as the macro in file.c */
110 #define TO_PATH(x) (SCHEME_PATHP(x) ? (x) : scheme_char_string_to_path(x))
111 
112 static void save_errno_values(int kind);
113 
114 /* This make hides pointerness from cdefstruct so that it
115    doesn't generate a mark/fixup action: */
116 #define NON_GCBALE_PTR(t) t*
117 
overflow_error(const char * who,const char * op,intptr_t a,intptr_t b)118 static void overflow_error(const char *who, const char *op, intptr_t a, intptr_t b)
119 {
120   scheme_contract_error(who, "arithmetic overflow",
121                         "operation", 0, op,
122                         "first argument", 1, scheme_make_integer(a),
123                         "first argument", 1, scheme_make_integer(b),
124                         NULL);
125 }
126 
mult_check_overflow(const char * who,intptr_t a,intptr_t b)127 static intptr_t mult_check_overflow(const char *who, intptr_t a, intptr_t b)
128 {
129   Scheme_Object *c;
130   c = scheme_bin_mult(scheme_make_integer(a), scheme_make_integer(b));
131   if (!SCHEME_INTP(c))
132     overflow_error(who, "multiply", a, b);
133   return SCHEME_INT_VAL(c);
134 }
135 
add_check_overflow(const char * who,intptr_t a,intptr_t b)136 static intptr_t add_check_overflow(const char *who, intptr_t a, intptr_t b)
137 {
138   Scheme_Object *c;
139   c = scheme_bin_plus(scheme_make_integer(a), scheme_make_integer(b));
140   if (!SCHEME_INTP(c))
141     overflow_error(who, "add", a, b);
142   return SCHEME_INT_VAL(c);
143 }
144 
145 /*****************************************************************************/
146 /* Library objects */
147 
148 /* ffi-lib structure definition */
149 static Scheme_Type ffi_lib_tag;
150 typedef struct ffi_lib_struct {
151   Scheme_Object so;
152   NON_GCBALE_PTR(rktio_dll_t) handle;
153   Scheme_Object* name;
154   int is_global;
155   int refcount;
156 } ffi_lib_struct;
157 #define SCHEME_FFILIBP(x) (SCHEME_TYPE(x)==ffi_lib_tag)
158 #define MYNAME "ffi-lib?"
foreign_ffi_lib_p(int argc,Scheme_Object * argv[])159 static Scheme_Object *foreign_ffi_lib_p(int argc, Scheme_Object *argv[])
160 {
161   return SCHEME_FFILIBP(argv[0]) ? scheme_true : scheme_false;
162 }
163 #undef MYNAME
164 /* 3m stuff for ffi_lib */
165 #ifdef MZ_PRECISE_GC
166 START_XFORM_SKIP;
ffi_lib_SIZE(void * p)167 int ffi_lib_SIZE(void *p) {
168   return gcBYTES_TO_WORDS(sizeof(ffi_lib_struct));
169 }
ffi_lib_MARK(void * p)170 int ffi_lib_MARK(void *p) {
171   ffi_lib_struct *s = (ffi_lib_struct *)p;
172   gcMARK(s->name);
173   return gcBYTES_TO_WORDS(sizeof(ffi_lib_struct));
174 }
ffi_lib_FIXUP(void * p)175 int ffi_lib_FIXUP(void *p) {
176   ffi_lib_struct *s = (ffi_lib_struct *)p;
177   gcFIXUP(s->name);
178   return gcBYTES_TO_WORDS(sizeof(ffi_lib_struct));
179 }
180 END_XFORM_SKIP;
181 #endif
182 
183 THREAD_LOCAL_DECL(static Scheme_Hash_Table *opened_libs);
184 
185 /* (ffi-lib filename no-error? global?) -> ffi-lib */
186 #define MYNAME "ffi-lib"
foreign_ffi_lib(int argc,Scheme_Object * argv[])187 static Scheme_Object *foreign_ffi_lib(int argc, Scheme_Object *argv[])
188 {
189   char *name;
190   Scheme_Object *path, *hashname;
191   rktio_dll_t *handle;
192   int as_global = 0;
193   ffi_lib_struct *lib;
194   if (!(SCHEME_PATH_STRINGP(argv[0]) || SCHEME_FALSEP(argv[0])))
195     scheme_wrong_contract(MYNAME, "(or/c string? #f)", 0, argc, argv);
196   as_global = ((argc > 2) && SCHEME_TRUEP(argv[2]));
197   /* leave the filename as given, the system will look for it */
198   /* (`#f' means open the executable) */
199   path = SCHEME_FALSEP(argv[0]) ? NULL : TO_PATH(argv[0]);
200   name = (path==NULL) ? NULL : SCHEME_PATH_VAL(path);
201   hashname = (Scheme_Object*)((name==NULL) ? "" : name);
202   lib = (ffi_lib_struct*)scheme_hash_get(opened_libs, hashname);
203   if (!lib) {
204     handle = rktio_dll_open(scheme_rktio, name, as_global);
205     if (!handle) {
206       char *msg;
207       msg = rktio_dll_get_error(scheme_rktio);
208       if (argc > 1 && SCHEME_TRUEP(argv[1])) {
209         if (msg) free(msg);
210         return scheme_false;
211       } else {
212         if (msg) {
213           msg = scheme_strdup_and_free(msg);
214           scheme_raise_exn(MZEXN_FAIL_FILESYSTEM,
215                            MYNAME": couldn't open %V (%s)", argv[0], msg);
216         } else
217           scheme_raise_exn(MZEXN_FAIL_FILESYSTEM,
218                            MYNAME": couldn't open %V (%R)", argv[0]);
219       }
220     }
221     lib = (ffi_lib_struct*)scheme_malloc_tagged(sizeof(ffi_lib_struct));
222     lib->so.type = ffi_lib_tag;
223     lib->handle = (handle);
224     lib->name = (argv[0]);
225     lib->is_global = (!name);
226     lib->refcount = (1);
227     scheme_hash_set(opened_libs, hashname, (Scheme_Object*)lib);
228     /* no dlclose finalizer - since the hash table always keeps a reference */
229     /* maybe add some explicit unload at some point */
230   } else
231     lib->refcount++;
232   return (Scheme_Object*)lib;
233 }
234 #undef MYNAME
235 
236 /* (ffi-lib-name ffi-lib) -> string */
237 #define MYNAME "ffi-lib-name"
foreign_ffi_lib_name(int argc,Scheme_Object * argv[])238 static Scheme_Object *foreign_ffi_lib_name(int argc, Scheme_Object *argv[])
239 {
240   if (!SCHEME_FFILIBP(argv[0]))
241     scheme_wrong_contract(MYNAME, "ffi-lib?", 0, argc, argv);
242   return ((ffi_lib_struct*)argv[0])->name;
243 }
244 #undef MYNAME
245 
246 /* (ffi-lib-unload ffi-lib) -> (void) */
247 #define MYNAME "ffi-lib-unload"
foreign_ffi_lib_unload(int argc,Scheme_Object * argv[])248 static Scheme_Object *foreign_ffi_lib_unload(int argc, Scheme_Object *argv[])
249 {
250   ffi_lib_struct *lib;
251 
252   if (!SCHEME_FFILIBP(argv[0]))
253     scheme_wrong_contract(MYNAME, "ffi-lib?", 0, argc, argv);
254 
255   lib = (ffi_lib_struct *)argv[0];
256   if (!lib->handle)
257     scheme_raise_exn(MZEXN_FAIL_FILESYSTEM,
258                      MYNAME": couldn't close already-closed lib %V",
259                      lib->name);
260 
261   --lib->refcount;
262   if (lib->refcount)
263     return scheme_void;
264 
265   if (rktio_dll_close(scheme_rktio, lib->handle)) {
266     Scheme_Object *hashname;
267 
268     lib->handle = NULL;
269 
270     if (SCHEME_FALSEP(lib->name))
271       hashname = (Scheme_Object *)"";
272     else {
273       hashname = TO_PATH(lib->name);
274       hashname = (Scheme_Object *)SCHEME_PATH_VAL(hashname);
275     }
276     scheme_hash_set(opened_libs, hashname, NULL);
277   } else {
278     char *msg;
279     msg = rktio_dll_get_error(scheme_rktio);
280     if (msg) {
281       msg = scheme_strdup_and_free(msg);
282       scheme_raise_exn(MZEXN_FAIL_FILESYSTEM,
283                        MYNAME": couldn't close %V (%s)", lib->name, msg);
284     } else
285       scheme_raise_exn(MZEXN_FAIL_FILESYSTEM,
286                        MYNAME": couldn't close %V (%R)", lib->name);
287   }
288 
289   return scheme_void;
290 }
291 #undef MYNAME
292 
293 /*****************************************************************************/
294 /* Pull pointers (mostly functions) out of ffi-lib objects */
295 
296 /* ffi-obj structure definition */
297 static Scheme_Type ffi_obj_tag;
298 typedef struct ffi_obj_struct {
299   Scheme_Object so;
300   NON_GCBALE_PTR(void) obj;
301   char* name;
302   NON_GCBALE_PTR(ffi_lib_struct) lib;
303 } ffi_obj_struct;
304 #define SCHEME_FFIOBJP(x) (SCHEME_TYPE(x)==ffi_obj_tag)
305 #define MYNAME "ffi-obj?"
foreign_ffi_obj_p(int argc,Scheme_Object * argv[])306 static Scheme_Object *foreign_ffi_obj_p(int argc, Scheme_Object *argv[])
307 {
308   return SCHEME_FFIOBJP(argv[0]) ? scheme_true : scheme_false;
309 }
310 #undef MYNAME
311 /* 3m stuff for ffi_obj */
312 #ifdef MZ_PRECISE_GC
313 START_XFORM_SKIP;
ffi_obj_SIZE(void * p)314 int ffi_obj_SIZE(void *p) {
315   return gcBYTES_TO_WORDS(sizeof(ffi_obj_struct));
316 }
ffi_obj_MARK(void * p)317 int ffi_obj_MARK(void *p) {
318   ffi_obj_struct *s = (ffi_obj_struct *)p;
319   gcMARK(s->name);
320   return gcBYTES_TO_WORDS(sizeof(ffi_obj_struct));
321 }
ffi_obj_FIXUP(void * p)322 int ffi_obj_FIXUP(void *p) {
323   ffi_obj_struct *s = (ffi_obj_struct *)p;
324   gcFIXUP(s->name);
325   return gcBYTES_TO_WORDS(sizeof(ffi_obj_struct));
326 }
327 END_XFORM_SKIP;
328 #endif
329 
330 /* (ffi-obj objname ffi-lib-or-libname) -> ffi-obj */
331 #define MYNAME "ffi-obj"
foreign_ffi_obj(int argc,Scheme_Object * argv[])332 static Scheme_Object *foreign_ffi_obj(int argc, Scheme_Object *argv[])
333 {
334   ffi_obj_struct *obj;
335   void *dlobj;
336   ffi_lib_struct *lib = NULL;
337   char *dlname;
338   if (SCHEME_FFILIBP(argv[1]))
339     lib = (ffi_lib_struct*)argv[1];
340   else if (SCHEME_PATH_STRINGP(argv[1]) || SCHEME_FALSEP(argv[1]))
341     lib = (ffi_lib_struct*)(foreign_ffi_lib(1,&argv[1]));
342   else
343     scheme_wrong_contract(MYNAME, "ffi-lib?", 1, argc, argv);
344   if (!SCHEME_BYTE_STRINGP(argv[0]))
345     scheme_wrong_contract(MYNAME, "bytes?", 0, argc, argv);
346   dlname = SCHEME_BYTE_STR_VAL(argv[0]);
347 
348   if (!lib->handle) {
349     scheme_raise_exn(MZEXN_FAIL_FILESYSTEM,
350                      MYNAME": couldn't get \"%s\" from already-closed %V",
351                      dlname, lib->name);
352   }
353 
354   dlobj = rktio_dll_find_object(scheme_rktio, lib->handle, dlname);
355   if (!dlobj) {
356     char *msg;
357     msg = rktio_dll_get_error(scheme_rktio);
358     if (msg) {
359       msg = scheme_strdup_and_free(msg);
360       scheme_raise_exn(MZEXN_FAIL_FILESYSTEM,
361                        MYNAME": couldn't get \"%s\" from %V (%s)",
362                        dlname, lib->name, msg);
363     } else
364       scheme_raise_exn(MZEXN_FAIL_FILESYSTEM,
365                        MYNAME": couldn't get \"%s\" from %V (%R)",
366                        dlname, lib->name);
367   }
368 
369   if (dlobj) {
370     obj = (ffi_obj_struct*)scheme_malloc_tagged(sizeof(ffi_obj_struct));
371     obj->so.type = ffi_obj_tag;
372     obj->obj = (dlobj);
373     obj->name = (dlname);
374     obj->lib = (lib);
375     return (Scheme_Object *)obj;
376   } else
377     return scheme_false;
378 }
379 #undef MYNAME
380 
381 /* (ffi-obj-lib ffi-obj) -> ffi-lib */
382 #define MYNAME "ffi-obj-lib"
foreign_ffi_obj_lib(int argc,Scheme_Object * argv[])383 static Scheme_Object *foreign_ffi_obj_lib(int argc, Scheme_Object *argv[])
384 {
385   if (!SCHEME_FFIOBJP(argv[0]))
386     scheme_wrong_contract(MYNAME, "ffi-obj?", 0, argc, argv);
387   return (Scheme_Object*)(((ffi_obj_struct*)argv[0])->lib);
388 }
389 #undef MYNAME
390 
391 /* (ffi-obj-name ffi-obj) -> string */
392 #define MYNAME "ffi-obj-name"
foreign_ffi_obj_name(int argc,Scheme_Object * argv[])393 static Scheme_Object *foreign_ffi_obj_name(int argc, Scheme_Object *argv[])
394 {
395   if (!SCHEME_FFIOBJP(argv[0]))
396     scheme_wrong_contract(MYNAME, "ffi-obj?", 0, argc, argv);
397   return scheme_make_byte_string(((ffi_obj_struct*)argv[0])->name);
398 }
399 #undef MYNAME
400 
401 /*****************************************************************************/
402 /* Type helpers */
403 
404 /* These are not defined in Racket because:
405  * - SCHEME_UINT_VAL is not really a simple accessor like other SCHEME_X_VALs
406  * - scheme_make_integer_from_unsigned behaves the same as the signed version
407  */
408 #define SCHEME_UINT_VAL(obj) ((unsigned)(SCHEME_INT_VAL(obj)))
409 #define scheme_make_integer_from_unsigned(i) \
410   ((Scheme_Object *)((((uintptr_t)i) << 1) | 0x1))
411 
412 #ifndef SIXTY_FOUR_BIT_INTEGERS
413 
414 /* longs and ints are really the same */
415 #define scheme_get_realint_val(x,y) \
416   scheme_get_int_val(x,(intptr_t*)(y))
417 #define scheme_get_unsigned_realint_val(x,y) \
418   scheme_get_unsigned_int_val(x,(uintptr_t*)(y))
419 #define scheme_make_realinteger_value \
420   scheme_make_integer_value
421 #define scheme_make_realinteger_value_from_unsigned \
422   scheme_make_integer_value_from_unsigned
423 
424 #else /* SIXTY_FOUR_BIT_INTEGERS defined */
425 
426 /* These will make sense in Racket when longs are longer than ints (needed
427  * for libffi's int32 types).  There is no need to deal with bignums because
428  * racket's fixnums are longs. */
scheme_get_realint_val(Scheme_Object * o,int * v)429 XFORM_NONGCING int scheme_get_realint_val(Scheme_Object *o, int *v)
430 {
431   if (SCHEME_INTP(o)) {
432     uintptr_t lv = SCHEME_INT_VAL(o);
433     int i = (int)lv;
434     if (i != lv)
435       return 0;
436     *v = i;
437     return 1;
438   } else return 0;
439 }
scheme_get_unsigned_realint_val(Scheme_Object * o,unsigned int * v)440 XFORM_NONGCING int scheme_get_unsigned_realint_val(Scheme_Object *o, unsigned int *v)
441 {
442   if (SCHEME_INTP(o)) {
443     uintptr_t lv = SCHEME_INT_VAL(o);
444     unsigned int i = (unsigned int)lv;
445     if (i != lv)
446       return 0;
447     *v = i;
448     return 1;
449   } else return 0;
450 }
451 #define scheme_make_realinteger_value(ri) \
452   scheme_make_integer((intptr_t)(ri))
453 #define scheme_make_realinteger_value_from_unsigned(ri) \
454   scheme_make_integer((uintptr_t)(ri))
455 
456 #endif /* SIXTY_FOUR_BIT_INTEGERS */
457 
get_byte_val(Scheme_Object * o,Tsint8 * _v)458 XFORM_NONGCING MZ_INLINE static int get_byte_val(Scheme_Object *o, Tsint8 *_v)
459 {
460   if (SCHEME_INTP(o)) {
461     intptr_t v = SCHEME_INT_VAL(o);
462     if ((v >= -128) && (v <= 127)) {
463       *_v = v;
464       return 1;
465     }
466   }
467   return 0;
468 }
469 
get_ubyte_val(Scheme_Object * o,Tuint8 * _v)470 XFORM_NONGCING MZ_INLINE static int get_ubyte_val(Scheme_Object *o, Tuint8 *_v)
471 {
472   if (SCHEME_INTP(o)) {
473     intptr_t v = SCHEME_INT_VAL(o);
474     if ((v >= 0) && (v <= 255)) {
475       *_v = v;
476       return 1;
477     }
478   }
479   return 0;
480 }
481 
get_short_val(Scheme_Object * o,Tsint16 * _v)482 XFORM_NONGCING MZ_INLINE static int get_short_val(Scheme_Object *o, Tsint16 *_v)
483 {
484   if (SCHEME_INTP(o)) {
485     intptr_t v = SCHEME_INT_VAL(o);
486     if ((v >= -32768) && (v <= 32767)) {
487       *_v = v;
488       return 1;
489     }
490   }
491   return 0;
492 }
493 
get_ushort_val(Scheme_Object * o,Tuint16 * _v)494 XFORM_NONGCING MZ_INLINE static int get_ushort_val(Scheme_Object *o, Tuint16 *_v)
495 {
496   if (SCHEME_INTP(o)) {
497     intptr_t v = SCHEME_INT_VAL(o);
498     if ((v >= 0) && (v <= 65536)) {
499       *_v = v;
500       return 1;
501     }
502   }
503   return 0;
504 }
505 
506 /* This is related to the section of scheme.h that defines mzlonglong. */
507 #ifndef INT64_AS_LONG_LONG
508 #ifdef  NO_LONG_LONG_TYPE
509 #ifndef SIXTY_FOUR_BIT_INTEGERS
510 #error foreign requires a 64-bit integer type type.
511 #endif
512 #endif
513 #endif
514 
515 #define SCHEME_FALSEP_OR_CHAR_STRINGP(o) (SCHEME_FALSEP(o) || SCHEME_CHAR_STRINGP(o))
516 
ucs4_string_or_null_to_ucs4_pointer(Scheme_Object * ucs)517 XFORM_NONGCING static mzchar *ucs4_string_or_null_to_ucs4_pointer(Scheme_Object *ucs)
518 {
519   if (SCHEME_FALSEP(ucs)) return NULL;
520   return SCHEME_CHAR_STR_VAL(ucs);
521 }
522 
ucs4_string_to_utf16_pointer(Scheme_Object * ucs)523 static unsigned short *ucs4_string_to_utf16_pointer(Scheme_Object *ucs)
524 {
525   intptr_t ulen;
526   unsigned short *res;
527   res = scheme_ucs4_to_utf16
528           (SCHEME_CHAR_STR_VAL(ucs), 0, SCHEME_CHAR_STRLEN_VAL(ucs),
529            NULL, -1, &ulen, 1);
530   res[ulen] = 0;
531   return res;
532 }
533 
ucs4_string_or_null_to_utf16_pointer(Scheme_Object * ucs)534 static unsigned short *ucs4_string_or_null_to_utf16_pointer(Scheme_Object *ucs)
535 {
536   if (SCHEME_FALSEP(ucs)) return NULL;
537   return ucs4_string_to_utf16_pointer(ucs);
538 }
539 
utf16_pointer_to_ucs4_string(unsigned short * utf)540 static Scheme_Object *utf16_pointer_to_ucs4_string(unsigned short *utf)
541 {
542   intptr_t ulen, end;
543   mzchar *res;
544   if (!utf) return scheme_false;
545   for (end=0; utf[end] != 0; end++) { /**/ }
546   res = scheme_utf16_to_ucs4(utf, 0, end, NULL, -1, &ulen, 1);
547   res[ulen] = 0;
548   return scheme_make_sized_char_string(res, ulen, 0);
549 }
550 
551 /*****************************************************************************/
552 /* Types */
553 
554 #define MZ_TYPE_CAST(t, e) (t)(e)
555 #define MZ_NO_TYPE_CAST(t, e) (e)
556 
557 /***********************************************************************
558  * The following are the only primitive types.
559  * The tricky part is figuring out what width-ed types correspond to
560  * what internal types.  Matthew says:
561  *   Racket expects to be compiled such that sizeof(int) == 4,
562  *   sizeof(intptr_t) == sizeof(void*), sizeof(short) >= 2,
563  *   sizeof(char) == 1, sizeof(float) == 4, and sizeof(double) == 8.
564  *   So, on a 64-bit OS, Racket expects only `long' and `intptr_t' to change.
565  **********************************************************************/
566 
567 /* returns #<void> when used as output type, not for input types. */
568 #define FOREIGN_void (1)
569 /* Type Name:   void
570  * LibFfi type: ffi_type_void
571  * C type:      -none-
572  * Predicate:   -none-
573  * Racket->C:   -none-
574  * S->C offset: 0
575  * C->Racket:   scheme_void
576  */
577 
578 #define FOREIGN_int8 (2)
579 /* Type Name:   int8
580  * LibFfi type: ffi_type_sint8
581  * C type:      Tsint8
582  * Predicate:   get_byte_val(<Scheme>,&aux)
583  * Racket->C:   -none- (set by the predicate)
584  * S->C offset: 0
585  * C->Racket:   scheme_make_integer(<C>)
586  */
587 
588 #define FOREIGN_uint8 (3)
589 /* Type Name:   uint8
590  * LibFfi type: ffi_type_uint8
591  * C type:      Tuint8
592  * Predicate:   get_ubyte_val(<Scheme>,&aux)
593  * Racket->C:   -none- (set by the predicate)
594  * S->C offset: 0
595  * C->Racket:   scheme_make_integer(<C>)
596  */
597 
598 #define FOREIGN_int16 (4)
599 /* Type Name:   int16
600  * LibFfi type: ffi_type_sint16
601  * C type:      Tsint16
602  * Predicate:   get_short_val(<Scheme>,&aux)
603  * Racket->C:   -none- (set by the predicate)
604  * S->C offset: 0
605  * C->Racket:   scheme_make_integer(<C>)
606  */
607 
608 #define FOREIGN_uint16 (5)
609 /* Type Name:   uint16
610  * LibFfi type: ffi_type_uint16
611  * C type:      Tuint16
612  * Predicate:   get_ushort_val(<Scheme>,&aux)
613  * Racket->C:   -none- (set by the predicate)
614  * S->C offset: 0
615  * C->Racket:   scheme_make_integer(<C>)
616  */
617 
618 /* Treats integers properly: */
619 #define FOREIGN_int32 (6)
620 /* Type Name:   int32
621  * LibFfi type: ffi_type_sint32
622  * C type:      Tsint32
623  * Predicate:   scheme_get_realint_val(<Scheme>,&aux)
624  * Racket->C:   -none- (set by the predicate)
625  * S->C offset: 0
626  * C->Racket:   scheme_make_realinteger_value(<C>)
627  */
628 
629 /* Treats integers properly: */
630 #define FOREIGN_uint32 (7)
631 /* Type Name:   uint32
632  * LibFfi type: ffi_type_uint32
633  * C type:      Tuint32
634  * Predicate:   scheme_get_unsigned_realint_val(<Scheme>,&aux)
635  * Racket->C:   -none- (set by the predicate)
636  * S->C offset: 0
637  * C->Racket:   scheme_make_realinteger_value_from_unsigned(<C>)
638  */
639 
640 #define FOREIGN_int64 (8)
641 /* Type Name:   int64
642  * LibFfi type: ffi_type_sint64
643  * C type:      Tsint64
644  * Predicate:   scheme_get_long_long_val(<Scheme>,&aux)
645  * Racket->C:   -none- (set by the predicate)
646  * S->C offset: 0
647  * C->Racket:   scheme_make_integer_value_from_long_long(<C>)
648  */
649 
650 #define FOREIGN_uint64 (9)
651 /* Type Name:   uint64
652  * LibFfi type: ffi_type_uint64
653  * C type:      Tuint64
654  * Predicate:   scheme_get_unsigned_long_long_val(<Scheme>,&aux)
655  * Racket->C:   -none- (set by the predicate)
656  * S->C offset: 0
657  * C->Racket:   scheme_make_integer_value_from_unsigned_long_long(<C>)
658  */
659 
660 /* This is like int32, but always assumes fixnum: */
661 #define FOREIGN_fixint (10)
662 /* Type Name:   fixint
663  * LibFfi type: ffi_type_sint32
664  * C type:      Tsint32
665  * Predicate:   SCHEME_INTP(<Scheme>)
666  * Racket->C:   SCHEME_INT_VAL(<Scheme>)
667  * S->C offset: 0
668  * C->Racket:   scheme_make_integer(<C>)
669  */
670 
671 /* This is like uint32, but always assumes fixnum: */
672 #define FOREIGN_ufixint (11)
673 /* Type Name:   ufixint
674  * LibFfi type: ffi_type_uint32
675  * C type:      Tuint32
676  * Predicate:   SCHEME_INTP(<Scheme>)
677  * Racket->C:   SCHEME_UINT_VAL(<Scheme>)
678  * S->C offset: 0
679  * C->Racket:   scheme_make_integer_from_unsigned(<C>)
680  */
681 
682 #ifndef SIXTY_FOUR_BIT_LONGS
683 #define ffi_type_smzlong ffi_type_sint32
684 #define ffi_type_umzlong ffi_type_uint32
685 #else /* SIXTY_FOUR_BIT_LONGS defined */
686 #define ffi_type_smzlong ffi_type_sint64
687 #define ffi_type_umzlong ffi_type_uint64
688 #endif /* SIXTY_FOUR_BIT_LONGS */
689 
690 #ifndef SIXTY_FOUR_BIT_INTEGERS
691 #define ffi_type_smzintptr ffi_type_sint32
692 #define ffi_type_umzintptr ffi_type_uint32
693 #else /* SIXTY_FOUR_BIT_INTEGERS defined */
694 #define ffi_type_smzintptr ffi_type_sint64
695 #define ffi_type_umzintptr ffi_type_uint64
696 #endif /* SIXTY_FOUR_BIT_INTEGERS */
697 
698 /* This is what mzscheme defines as intptr, assuming fixnums: */
699 #define FOREIGN_fixnum (12)
700 /* Type Name:   fixnum
701  * LibFfi type: ffi_type_smzintptr
702  * C type:      intptr_t
703  * Predicate:   SCHEME_INTP(<Scheme>)
704  * Racket->C:   SCHEME_INT_VAL(<Scheme>)
705  * S->C offset: 0
706  * C->Racket:   scheme_make_integer(<C>)
707  */
708 
709 /* This is what mzscheme defines as uintptr, assuming fixnums: */
710 #define FOREIGN_ufixnum (13)
711 /* Type Name:   ufixnum
712  * LibFfi type: ffi_type_umzintptr
713  * C type:      uintptr_t
714  * Predicate:   SCHEME_INTP(<Scheme>)
715  * Racket->C:   SCHEME_UINT_VAL(<Scheme>)
716  * S->C offset: 0
717  * C->Racket:   scheme_make_integer_from_unsigned(<C>)
718  */
719 
720 #define FOREIGN_float (14)
721 /* Type Name:   float
722  * LibFfi type: ffi_type_float
723  * C type:      float
724  * Predicate:   SCHEME_FLOATP(<Scheme>)
725  * Racket->C:   SCHEME_FLOAT_VAL(<Scheme>)
726  * S->C offset: 0
727  * C->Racket:   scheme_make_double(<C>)
728  */
729 
730 #define FOREIGN_double (15)
731 /* Type Name:   double
732  * LibFfi type: ffi_type_double
733  * C type:      double
734  * Predicate:   SCHEME_FLOATP(<Scheme>)
735  * Racket->C:   SCHEME_FLOAT_VAL(<Scheme>)
736  * S->C offset: 0
737  * C->Racket:   scheme_make_double(<C>)
738  */
739 
740 #ifdef _MSC_VER
741 struct struct_align_slongdouble {
742   char c;
743   long_double x;
744 };
745 const ffi_type ffi_type_slongdouble = {
746   sizeof(long_double),
747   offsetof(struct struct_align_slongdouble, x),
748   FFI_TYPE_STRUCT, NULL
749 };
750 #else /* _MSC_VER undefined */
751 #define ffi_type_slongdouble ffi_type_longdouble
752 #endif /* _MSC_VER */
753 #ifdef MZ_LONG_DOUBLE
754 #define SCHEME_MAYBE_LONG_DBL_VAL(x) SCHEME_LONG_DBL_VAL(x)
755 #else /* MZ_LONG_DOUBLE undefined */
756 #define SCHEME_MAYBE_LONG_DBL_VAL(x) unsupported_long_double_val()
unsupported_long_double_val()757 static mz_long_double unsupported_long_double_val() {
758   scheme_raise_exn(MZEXN_FAIL_UNSUPPORTED, "_longdouble: " NOT_SUPPORTED_STR);
759   return 0.0;
760 }
761 #endif /* MZ_LONG_DOUBLE */
762 #ifdef MZ_LONG_DOUBLE
763 #define scheme_make_maybe_long_double(x) scheme_make_long_double(x)
764 #else /* MZ_LONG_DOUBLE undefined */
765 #define scheme_make_maybe_long_double(x) unsupported_make_long_double()
unsupported_make_long_double()766 static Scheme_Object *unsupported_make_long_double() {
767   scheme_raise_exn(MZEXN_FAIL_UNSUPPORTED, "_longdouble: " NOT_SUPPORTED_STR);
768   return NULL;
769 }
770 #endif /* MZ_LONG_DOUBLE */
771 
772 #define FOREIGN_longdouble (16)
773 /* Type Name:   longdouble
774  * LibFfi type: ffi_type_slongdouble
775  * C type:      mz_long_double
776  * Predicate:   SCHEME_LONG_DBLP(<Scheme>)
777  * Racket->C:   SCHEME_MAYBE_LONG_DBL_VAL(<Scheme>)
778  * S->C offset: 0
779  * C->Racket:   scheme_make_maybe_long_double(<C>)
780  */
781 
782 
783 /* A double that will coerce numbers to doubles: */
784 #define FOREIGN_doubleS (17)
785 /* Type Name:   double* (doubleS)
786  * LibFfi type: ffi_type_double
787  * C type:      double
788  * Predicate:   SCHEME_REALP(<Scheme>)
789  * Racket->C:   scheme_real_to_double(<Scheme>)
790  * S->C offset: 0
791  * C->Racket:   scheme_make_double(<C>)
792  */
793 
794 /* Booleans -- implemented as an int which is 1 or 0: */
795 #define FOREIGN_bool (18)
796 /* Type Name:   bool
797  * LibFfi type: ffi_type_sint
798  * C type:      int
799  * Predicate:   1
800  * Racket->C:   SCHEME_TRUEP(<Scheme>)
801  * S->C offset: 0
802  * C->Racket:   (<C>?scheme_true:scheme_false)
803  */
804 
805 #if SIZEOF_BOOL == 0
806 typedef signed char stdbool;
807 # define ffi_type_stdbool ffi_type_sint8
808 #else /* SIZEOF_BOOL == 0  */
809 typedef bool stdbool;
810 #if SIZEOF_BOOL == 1
811 # define ffi_type_stdbool ffi_type_sint8
812 #else /* SIZEOF_BOOL == 1  */
813 #if SIZEOF_BOOL == 2
814 # define ffi_type_stdbool ffi_type_sint16
815 #else /* SIZEOF_BOOL == 2  */
816 #if SIZEOF_BOOL == 4
817 # define ffi_type_stdbool ffi_type_sint32
818 #else /* SIZEOF_BOOL == 4  */
819 #if SIZEOF_BOOL == 8
820 # define ffi_type_stdbool ffi_type_sint64
821 #else /* SIZEOF_BOOL == 8  */
822 /* ??? Pick something */
823 # define ffi_type_stdbool ffi_type_int
824 #endif /* SIZEOF_BOOL == 8 */
825 #endif /* SIZEOF_BOOL == 4 */
826 #endif /* SIZEOF_BOOL == 2 */
827 #endif /* SIZEOF_BOOL == 1 */
828 #endif /* SIZEOF_BOOL == 0 */
829 
830 /* Booleans -- implemented as an int which is 1 or 0: */
831 #define FOREIGN_stdbool (19)
832 /* Type Name:   stdbool
833  * LibFfi type: ffi_type_stdbool
834  * C type:      stdbool
835  * Predicate:   1
836  * Racket->C:   SCHEME_TRUEP(<Scheme>)
837  * S->C offset: 0
838  * C->Racket:   (<C>?scheme_true:scheme_false)
839  */
840 
841 /* Strings -- no copying is done (when possible).
842  * #f is not NULL only for byte-strings, for other strings it is
843  * meaningless to use NULL. */
844 
845 #define FOREIGN_string_ucs_4 (20)
846 /* Type Name:   string/ucs-4 (string_ucs_4)
847  * LibFfi type: ffi_type_gcpointer
848  * C type:      mzchar*
849  * Predicate:   SCHEME_FALSEP_OR_CHAR_STRINGP(<Scheme>)
850  * Racket->C:   ucs4_string_or_null_to_ucs4_pointer(<Scheme>)
851  * S->C offset: 0
852  * C->Racket:   scheme_make_char_string_without_copying(<C>)
853  */
854 
855 #define FOREIGN_string_utf_16 (21)
856 /* Type Name:   string/utf-16 (string_utf_16)
857  * LibFfi type: ffi_type_gcpointer
858  * C type:      unsigned short*
859  * Predicate:   SCHEME_FALSEP_OR_CHAR_STRINGP(<Scheme>)
860  * Racket->C:   ucs4_string_or_null_to_utf16_pointer(<Scheme>)
861  * S->C offset: 0
862  * C->Racket:   utf16_pointer_to_ucs4_string(<C>)
863  */
864 
865 /* Byte strings -- not copying C strings, #f is NULL.
866  * (note: these are not like char* which is just a pointer) */
867 
868 #define FOREIGN_bytes (22)
869 /* Type Name:   bytes
870  * LibFfi type: ffi_type_gcpointer
871  * C type:      char*
872  * Predicate:   SCHEME_FALSEP(<Scheme>)||SCHEME_BYTE_STRINGP(<Scheme>)
873  * Racket->C:   SCHEME_FALSEP(<Scheme>)?NULL:SCHEME_BYTE_STR_VAL(<Scheme>)
874  * S->C offset: 0
875  * C->Racket:   (<C>==NULL)?scheme_false:scheme_make_byte_string_without_copying(<C>)
876  */
877 
878 #define FOREIGN_path (23)
879 /* Type Name:   path
880  * LibFfi type: ffi_type_gcpointer
881  * C type:      char*
882  * Predicate:   SCHEME_FALSEP(<Scheme>)||SCHEME_PATH_STRINGP(<Scheme>)
883  * Racket->C:   SCHEME_FALSEP(<Scheme>)?NULL:SCHEME_PATH_VAL(TO_PATH(<Scheme>))
884  * S->C offset: 0
885  * C->Racket:   (<C>==NULL)?scheme_false:scheme_make_path_without_copying(<C>)
886  */
887 
888 #define FOREIGN_symbol (24)
889 /* Type Name:   symbol
890  * LibFfi type: ffi_type_pointer
891  * C type:      char*
892  * Predicate:   SCHEME_SYMBOLP(<Scheme>)
893  * Racket->C:   SCHEME_SYM_VAL(<Scheme>)
894  * S->C offset: 0
895  * C->Racket:   scheme_intern_symbol(<C>)
896  */
897 
898 /* This is for any C pointer: #f is NULL, cpointer values as well as
899  * ffi-obj and string values pass their pointer.  When used as a return
900  * value, either a cpointer object or #f is returned. */
901 #define FOREIGN_pointer (25)
902 /* Type Name:   pointer
903  * LibFfi type: ffi_type_pointer
904  * C type:      void*
905  * Predicate:   SCHEME_FFIANYPTRP(<Scheme>)
906  * Racket->C:   SCHEME_FFIANYPTR_VAL(<Scheme>)
907  * S->C offset: FFIANYPTR
908  * C->Racket:   scheme_make_foreign_external_cpointer(<C>)
909  */
910 
911 #define FOREIGN_gcpointer (26)
912 /* Type Name:   gcpointer
913  * LibFfi type: ffi_type_gcpointer
914  * C type:      void*
915  * Predicate:   SCHEME_FFIANYPTRP(<Scheme>)
916  * Racket->C:   SCHEME_FFIANYPTR_VAL(<Scheme>)
917  * S->C offset: FFIANYPTR
918  * C->Racket:   scheme_make_foreign_cpointer(<C>)
919  */
920 
921 /* This is used for passing and Scheme_Object* value as is.  Useful for
922  * functions that know about Scheme_Object*s, like Racket's. */
923 #define FOREIGN_scheme (27)
924 /* Type Name:   scheme
925  * LibFfi type: ffi_type_gcpointer
926  * C type:      Scheme_Object*
927  * Predicate:   1
928  * Racket->C:   <Scheme>
929  * S->C offset: 0
930  * C->Racket:   <C>
931  */
932 
933 /* Special type, not actually used for anything except to mark values
934  * that are treated like pointers but not referenced.  Used for
935  * creating function types. */
936 #define FOREIGN_fpointer (28)
937 /* Type Name:   fpointer
938  * LibFfi type: ffi_type_pointer
939  * C type:      void*
940  * Predicate:   -none-
941  * Racket->C:   -none-
942  * S->C offset: 0
943  * C->Racket:   -none-
944  */
945 
946 typedef union _ForeignAny {
947   Tsint8 x_int8;
948   Tuint8 x_uint8;
949   Tsint16 x_int16;
950   Tuint16 x_uint16;
951   Tsint32 x_int32;
952   Tuint32 x_uint32;
953   Tsint64 x_int64;
954   Tuint64 x_uint64;
955   Tsint32 x_fixint;
956   Tuint32 x_ufixint;
957   intptr_t x_fixnum;
958   uintptr_t x_ufixnum;
959   float x_float;
960   double x_double;
961   mz_long_double x_longdouble;
962   double x_doubleS;
963   int x_bool;
964   stdbool x_stdbool;
965   mzchar* x_string_ucs_4;
966   unsigned short* x_string_utf_16;
967   char* x_bytes;
968   char* x_path;
969   char* x_symbol;
970   void* x_pointer;
971   void* x_gcpointer;
972   Scheme_Object* x_scheme;
973   void* x_fpointer;
974 } ForeignAny;
975 
976 /* This is a tag that is used to identify user-made struct types. */
977 #define FOREIGN_struct (29)
978 #define FOREIGN_array (30)
979 #define FOREIGN_union (31)
980 
is_gcable_pointer(Scheme_Object * o)981 XFORM_NONGCING static int is_gcable_pointer(Scheme_Object *o) {
982   if (SCHEME_FFIOBJP(o)) return 0;
983   return (!SCHEME_CPTRP(o)
984           || !(SCHEME_CPTR_FLAGS(o) & 0x1));
985 }
986 
987 /*****************************************************************************/
988 /* Type objects */
989 
990 /* This struct is used for both user types and primitive types (including
991  * struct types).  If it is a user type then basetype will be another ctype,
992  * otherwise,
993  * - if it's a primitive type, then basetype will be a symbol naming that type
994  * - if it's a struct or union, then basetype will be the list of ctypes that
995  *   made this struct, prefixed with a symbol if the allocation mode is not 'atomic
996  * scheme_to_c will have the &ffi_type pointer, and c_to_scheme will have an
997  * integer (a label value) for non-struct type.  (Note that the
998  * integer is not really needed, since it is possible to identify the
999  * type by the basetype field.)
1000  */
1001 /* ctype structure definition */
1002 #define ctype_tag scheme_ctype_type
1003 typedef struct ctype_struct {
1004   Scheme_Object so;
1005   Scheme_Object* basetype;
1006   Scheme_Object* scheme_to_c;
1007   Scheme_Object* c_to_scheme;
1008 } ctype_struct;
1009 #define SCHEME_CTYPEP(x) (SCHEME_TYPE(x)==ctype_tag)
1010 #define MYNAME "ctype?"
foreign_ctype_p(int argc,Scheme_Object * argv[])1011 static Scheme_Object *foreign_ctype_p(int argc, Scheme_Object *argv[])
1012 {
1013   return SCHEME_CTYPEP(argv[0]) ? scheme_true : scheme_false;
1014 }
1015 #undef MYNAME
1016 /* 3m stuff for ctype */
1017 #ifdef MZ_PRECISE_GC
1018 START_XFORM_SKIP;
ctype_SIZE(void * p)1019 int ctype_SIZE(void *p) {
1020   return gcBYTES_TO_WORDS(sizeof(ctype_struct));
1021 }
ctype_MARK(void * p)1022 int ctype_MARK(void *p) {
1023   ctype_struct *s = (ctype_struct *)p;
1024   gcMARK(s->basetype);
1025   gcMARK(s->scheme_to_c);
1026   gcMARK(s->c_to_scheme);
1027   return gcBYTES_TO_WORDS(sizeof(ctype_struct));
1028 }
ctype_FIXUP(void * p)1029 int ctype_FIXUP(void *p) {
1030   ctype_struct *s = (ctype_struct *)p;
1031   gcFIXUP(s->basetype);
1032   gcFIXUP(s->scheme_to_c);
1033   gcFIXUP(s->c_to_scheme);
1034   return gcBYTES_TO_WORDS(sizeof(ctype_struct));
1035 }
1036 END_XFORM_SKIP;
1037 #endif
1038 
1039 static ffi_type ffi_type_gcpointer;
1040 
1041 #define CTYPE_BASETYPE(x)  (((ctype_struct*)(x))->basetype)
1042 #define CTYPE_USERP(x)     (CTYPE_BASETYPE(x) != NULL && SCHEME_CTYPEP(CTYPE_BASETYPE(x)))
1043 #define CTYPE_PRIMP(x)     (!CTYPE_USERP(x))
1044 #define CTYPE_PRIMTYPE(x)  ((ffi_type*)(((ctype_struct*)(x))->scheme_to_c))
1045 #define CTYPE_PRIMLABEL(x) ((intptr_t)(((ctype_struct*)(x))->c_to_scheme))
1046 #define CTYPE_USER_S2C(x)  (((ctype_struct*)(x))->scheme_to_c)
1047 #define CTYPE_USER_C2S(x)  (((ctype_struct*)(x))->c_to_scheme)
1048 
1049 #define CTYPE_ARG_PRIMTYPE(x) ((CTYPE_PRIMLABEL(x) == FOREIGN_array) ? &ffi_type_pointer : CTYPE_PRIMTYPE(x))
1050 
1051 /* Returns #f for primitive types. */
1052 #define MYNAME "ctype-basetype"
foreign_ctype_basetype(int argc,Scheme_Object * argv[])1053 static Scheme_Object *foreign_ctype_basetype(int argc, Scheme_Object *argv[])
1054 {
1055   Scheme_Object *r;
1056   if (!SCHEME_CTYPEP(argv[0]))
1057     scheme_wrong_contract(MYNAME, "ctype?", 0, argc, argv);
1058   r = CTYPE_BASETYPE(argv[0]);
1059   if (SCHEME_PAIRP(r) && SCHEME_SYMBOLP(SCHEME_CAR(r))) {
1060     /* strip allocation mode for struct/union */
1061     r = SCHEME_CDR(r);
1062   }
1063   return r;
1064 }
1065 #undef MYNAME
1066 
1067 #define MYNAME "ctype-scheme->c"
foreign_ctype_scheme_to_c(int argc,Scheme_Object * argv[])1068 static Scheme_Object *foreign_ctype_scheme_to_c(int argc, Scheme_Object *argv[])
1069 {
1070   if (!SCHEME_CTYPEP(argv[0]))
1071     scheme_wrong_contract(MYNAME, "ctype?", 0, argc, argv);
1072   return (CTYPE_PRIMP(argv[0])) ? scheme_false :
1073            ((ctype_struct*)(argv[0]))->scheme_to_c;
1074 }
1075 #undef MYNAME
1076 
1077 #define MYNAME "ctype-c->scheme"
foreign_ctype_c_to_scheme(int argc,Scheme_Object * argv[])1078 static Scheme_Object *foreign_ctype_c_to_scheme(int argc, Scheme_Object *argv[])
1079 {
1080   if (!SCHEME_CTYPEP(argv[0]))
1081     scheme_wrong_contract(MYNAME, "ctype?", 0, argc, argv);
1082   return (CTYPE_PRIMP(argv[0])) ? scheme_false :
1083            ((ctype_struct*)(argv[0]))->c_to_scheme;
1084 }
1085 #undef MYNAME
1086 
1087 /* Returns a primitive type, or NULL if not a type */
get_ctype_base(Scheme_Object * type)1088 XFORM_NONGCING static Scheme_Object *get_ctype_base(Scheme_Object *type)
1089 {
1090   if (!SCHEME_CTYPEP(type)) return NULL;
1091   while (CTYPE_USERP(type)) { type = CTYPE_BASETYPE(type); }
1092   return type;
1093 }
1094 
1095 /* Returns the size, 0 for void, -1 if no such type */
ctype_sizeof(Scheme_Object * type)1096 XFORM_NONGCING static intptr_t ctype_sizeof(Scheme_Object *type)
1097 {
1098   type = get_ctype_base(type);
1099   if (type == NULL) return -1;
1100   switch (CTYPE_PRIMLABEL(type)) {
1101   case FOREIGN_void: return 0;
1102   case FOREIGN_int8: return sizeof(Tsint8);
1103   case FOREIGN_uint8: return sizeof(Tuint8);
1104   case FOREIGN_int16: return sizeof(Tsint16);
1105   case FOREIGN_uint16: return sizeof(Tuint16);
1106   case FOREIGN_int32: return sizeof(Tsint32);
1107   case FOREIGN_uint32: return sizeof(Tuint32);
1108   case FOREIGN_int64: return sizeof(Tsint64);
1109   case FOREIGN_uint64: return sizeof(Tuint64);
1110   case FOREIGN_fixint: return sizeof(Tsint32);
1111   case FOREIGN_ufixint: return sizeof(Tuint32);
1112   case FOREIGN_fixnum: return sizeof(intptr_t);
1113   case FOREIGN_ufixnum: return sizeof(uintptr_t);
1114   case FOREIGN_float: return sizeof(float);
1115   case FOREIGN_double: return sizeof(double);
1116   case FOREIGN_longdouble: return sizeof(mz_long_double);
1117   case FOREIGN_doubleS: return sizeof(double);
1118   case FOREIGN_bool: return sizeof(int);
1119   case FOREIGN_stdbool: return sizeof(stdbool);
1120   case FOREIGN_string_ucs_4: return sizeof(mzchar*);
1121   case FOREIGN_string_utf_16: return sizeof(unsigned short*);
1122   case FOREIGN_bytes: return sizeof(char*);
1123   case FOREIGN_path: return sizeof(char*);
1124   case FOREIGN_symbol: return sizeof(char*);
1125   case FOREIGN_pointer: return sizeof(void*);
1126   case FOREIGN_gcpointer: return sizeof(void*);
1127   case FOREIGN_scheme: return sizeof(Scheme_Object*);
1128   case FOREIGN_fpointer: return sizeof(void*);
1129   /* for structs and arrays */
1130   default: return CTYPE_PRIMTYPE(type)->size;
1131   }
1132 }
1133 
1134 /* (make-ctype basetype scheme->c c->scheme) -> ctype */
1135 /* The scheme->c can throw type errors to check for valid arguments */
1136 /* a #f means no conversion function, if both are #f -- then just return the */
1137 /* basetype. */
1138 #define MYNAME "make-ctype"
foreign_make_ctype(int argc,Scheme_Object * argv[])1139 static Scheme_Object *foreign_make_ctype(int argc, Scheme_Object *argv[])
1140 {
1141   ctype_struct *type;
1142   if (!SCHEME_CTYPEP(argv[0]))
1143     scheme_wrong_contract(MYNAME, "ctype?", 0, argc, argv);
1144   else if (!(SCHEME_FALSEP(argv[1]) || SCHEME_PROCP(argv[1])))
1145     scheme_wrong_contract(MYNAME, "(or/c procedure? #f)", 1, argc, argv);
1146   else if (!(SCHEME_FALSEP(argv[2]) || SCHEME_PROCP(argv[2])))
1147     scheme_wrong_contract(MYNAME, "(or/c procedure? #f)", 2, argc, argv);
1148   else if (SCHEME_FALSEP(argv[1]) && SCHEME_FALSEP(argv[2]))
1149     return argv[0];
1150   else {
1151     type = (ctype_struct*)scheme_malloc_tagged(sizeof(ctype_struct));
1152     type->so.type = ctype_tag;
1153     type->basetype = (argv[0]);
1154     type->scheme_to_c = (argv[1]);
1155     type->c_to_scheme = (argv[2]);
1156     return (Scheme_Object*)type;
1157   }
1158   return NULL; /* hush the compiler */
1159 }
1160 #undef MYNAME
1161 
1162 /* see below */
free_libffi_type(void * ignored,void * p)1163 static void free_libffi_type(void *ignored, void *p)
1164 {
1165   free(((ffi_type*)p)->elements);
1166   free(p);
1167 }
1168 
free_libffi_type_two_layers(void * ignored,void * p)1169 static void free_libffi_type_two_layers(void *ignored, void *p)
1170 {
1171   int i;
1172 
1173   for (i = 0; ((ffi_type*)p)->elements[i]; i++) {
1174     free(((ffi_type*)p)->elements[i]);
1175   }
1176   free_libffi_type(ignored, p);
1177 }
1178 
1179 /*****************************************************************************/
1180 /* ABI spec */
1181 
1182 static Scheme_Object *default_sym;
1183 static Scheme_Object *stdcall_sym;
1184 static Scheme_Object *sysv_sym;
1185 
sym_to_abi(const char * who,Scheme_Object * sym)1186 static ffi_abi sym_to_abi(const char *who, Scheme_Object *sym)
1187 {
1188   if (SCHEME_FALSEP(sym) || SAME_OBJ(sym, default_sym))
1189     return FFI_DEFAULT_ABI;
1190   else if (SAME_OBJ(sym, sysv_sym)) {
1191 #if defined(WINDOWS_DYNAMIC_LOAD) && !defined(_WIN64)
1192     return FFI_SYSV;
1193 #else
1194     scheme_signal_error("%s: ABI not implemented: %V", who, sym);
1195 #endif
1196   } else if (SAME_OBJ(sym, stdcall_sym)) {
1197 #if defined(WINDOWS_DYNAMIC_LOAD) && !defined(_WIN64)
1198     return FFI_STDCALL;
1199 #else
1200     scheme_signal_error("%s: ABI not implemented: %V", who, sym);
1201 #endif
1202   } else {
1203     scheme_signal_error("%s: unknown ABI: %V", who, sym);
1204   }
1205   return 0; /* hush the compiler */
1206 }
1207 
1208 /* helper macro */
1209 #define GET_ABI(name,n) \
1210   ((argc > (n)) ? sym_to_abi((name),argv[n]) : FFI_DEFAULT_ABI)
1211 
1212 /*****************************************************************************/
1213 /* cstruct types */
1214 
wrong_void(const char * who,Scheme_Object * list_element,int specifically_void,int which,int argc,Scheme_Object ** argv)1215 static void wrong_void(const char *who, Scheme_Object *list_element, int specifically_void,
1216                        int which, int argc, Scheme_Object **argv)
1217 {
1218   intptr_t len;
1219   char *s;
1220 
1221   if (argc > 1)
1222     s = scheme_make_arg_lines_string("  ", which, argc, argv, &len);
1223   else
1224     s = NULL;
1225 
1226   if (list_element) {
1227     scheme_contract_error(who,
1228                           (specifically_void
1229                            ? "C type within list is based on _void"
1230                            : "C type within list has a zero size"),
1231                           "C type", 1, list_element,
1232                           "list", 1, argv[which],
1233                           s ? "other arguments" : NULL, 0, s,
1234                           NULL);
1235   } else
1236     scheme_contract_error(who,
1237                           (specifically_void
1238                            ? "given C type is based on _void"
1239                            : "given C type has a zero size"),
1240                           "given C type", 1, argv[which],
1241                           s ? "other arguments" : NULL, 0, s,
1242                           NULL);
1243 }
1244 
1245 /* (make-cstruct-type types [abi alignment malloc-mode]) -> ctype */
1246 /* This creates a new primitive type that is a struct.  This type can be used
1247  * with cpointer objects, except that the contents is used rather than the
1248  * pointer value.  Marshaling to lists or whatever should be done in Racket. */
1249 #define MYNAME "make-cstruct-type"
foreign_make_cstruct_type(int argc,Scheme_Object * argv[])1250 static Scheme_Object *foreign_make_cstruct_type(int argc, Scheme_Object *argv[])
1251 {
1252   Scheme_Object *p, *base;
1253   /* since ffi_type objects can be used in callbacks, they are allocated using
1254    * malloc so they don't move, and they are freed when the Scheme object is
1255    * GCed. */
1256   GC_CAN_IGNORE ffi_type **elements, *libffi_type, **dummy;
1257   ctype_struct *type;
1258   ffi_cif cif;
1259   int i, nargs, with_alignment;
1260   ffi_abi abi;
1261   Scheme_Object *fields = argv[0];
1262   nargs = scheme_proper_list_length(fields);
1263   if (nargs <= 0) scheme_wrong_contract(MYNAME, "(non-empty-listof ctype?)", 0, argc, argv);
1264   abi = GET_ABI(MYNAME,1);
1265   if (argc > 2) {
1266     if (!SCHEME_FALSEP(argv[2])) {
1267       if (!SAME_OBJ(argv[2], scheme_make_integer(1))
1268           && !SAME_OBJ(argv[2], scheme_make_integer(2))
1269           && !SAME_OBJ(argv[2], scheme_make_integer(4))
1270           && !SAME_OBJ(argv[2], scheme_make_integer(8))
1271           && !SAME_OBJ(argv[2], scheme_make_integer(16)))
1272         scheme_wrong_contract(MYNAME, "(or/c 1 2 4 8 16 #f)", 2, argc, argv);
1273       with_alignment = SCHEME_INT_VAL(argv[2]);
1274     } else
1275       with_alignment = 0;
1276     if (argc > 3) {
1277       if (!SAME_OBJ(argv[3], atomic_sym)) {
1278         (void)mode_to_allocator(MYNAME, argv[3]);
1279         fields = scheme_make_pair(argv[3], fields);
1280       }
1281     }
1282   } else
1283     with_alignment = 0;
1284 
1285     /* allocate the type elements */
1286   elements = malloc((nargs+1) * sizeof(ffi_type*));
1287   elements[nargs] = NULL;
1288   for (i=0, p=argv[0]; i<nargs; i++, p=SCHEME_CDR(p)) {
1289     if (NULL == (base = get_ctype_base(SCHEME_CAR(p))))
1290       scheme_wrong_contract(MYNAME, "(non-empty-listof ctype?)", 0, argc, argv);
1291     if (CTYPE_PRIMLABEL(base) == FOREIGN_void)
1292       wrong_void(MYNAME, SCHEME_CAR(p), 1, 0, argc, argv);
1293     elements[i] = CTYPE_PRIMTYPE(base);
1294     if (with_alignment) {
1295       /* copy the type to set an alignment: */
1296       libffi_type = malloc(sizeof(ffi_type));
1297       memcpy(libffi_type, elements[i], sizeof(ffi_type));
1298       elements[i] = libffi_type;
1299       if (with_alignment < elements[i]->alignment)
1300         elements[i]->alignment = with_alignment;
1301     }
1302   }
1303 
1304   /* allocate the new libffi type object */
1305   libffi_type = malloc(sizeof(ffi_type));
1306   libffi_type->size      = 0;
1307   libffi_type->alignment = 0;
1308   libffi_type->type      = FFI_TYPE_STRUCT;
1309   libffi_type->elements  = elements;
1310   /* use ffi_prep_cif to set the size and alignment information */
1311   dummy = &libffi_type;
1312   if (ffi_prep_cif(&cif, abi, 1, &ffi_type_void, dummy) != FFI_OK)
1313     scheme_signal_error("internal error: ffi_prep_cif did not return FFI_OK");
1314   type = (ctype_struct*)scheme_malloc_tagged(sizeof(ctype_struct));
1315   type->so.type = ctype_tag;
1316   type->basetype = (fields);
1317   type->scheme_to_c = ((Scheme_Object*)libffi_type);
1318   type->c_to_scheme = ((Scheme_Object*)FOREIGN_struct);
1319   if (with_alignment)
1320     scheme_register_finalizer(type, free_libffi_type_two_layers, libffi_type, NULL, NULL);
1321   else
1322     scheme_register_finalizer(type, free_libffi_type, libffi_type, NULL, NULL);
1323   return (Scheme_Object*)type;
1324 }
1325 #undef MYNAME
1326 
1327 /*****************************************************************************/
1328 /* array types */
1329 
wrong_intptr(const char * who,int which,int argc,Scheme_Object ** argv)1330 static void wrong_intptr(const char *who, int which, int argc, Scheme_Object **argv)
1331 {
1332   if (!SCHEME_INTP(argv[which]) && !SCHEME_BIGNUMP(argv[which])) {
1333     scheme_wrong_contract(who, "exact-integer?", which, argc, argv);
1334   } else {
1335     intptr_t len;
1336     char *s;
1337 
1338     if (argc > 1)
1339       s = scheme_make_arg_lines_string("  ", which, argc, argv, &len);
1340     else
1341       s = NULL;
1342 
1343     scheme_contract_error(who,
1344                           "given integer does not fit into the _intptr type",
1345                           "given integer", 1, argv[which],
1346                           s ? "other arguments" : NULL, 0, s,
1347                           NULL);
1348   }
1349 }
1350 
1351 #if defined(__aarch64__)
1352 # define SMALL_ARRAY_THRESHOLD 64
1353 #else
1354 # define SMALL_ARRAY_THRESHOLD 32
1355 #endif
1356 
1357 /* (make-array-type type len) -> ctype */
1358 /* This creates a new primitive type that is an array. An array is the
1359  * same as a cpointer as an argument, but it behave differently within
1360  * a struct or for allocation. Marshaling to lists or whatever should
1361  * be done in Racket. */
1362 #define MYNAME "make-array-type"
foreign_make_array_type(int argc,Scheme_Object * argv[])1363 static Scheme_Object *foreign_make_array_type(int argc, Scheme_Object *argv[])
1364 {
1365   Scheme_Object *base, *basetype;
1366   GC_CAN_IGNORE ffi_type *libffi_type, **elements;
1367   ctype_struct *type;
1368   intptr_t len, size;
1369 
1370   if (NULL == (base = get_ctype_base(argv[0])))
1371     scheme_wrong_contract(MYNAME, "ctype?", 0, argc, argv);
1372   if (!scheme_get_int_val(argv[1], &len) || (len < 0)) {
1373     if ((SCHEME_INTP(argv[1]) && SCHEME_INT_VAL(argv[1]) > 0)
1374         || (SCHEME_BIGNUMP(argv[1]) && SCHEME_BIGPOS(argv[1])))
1375       wrong_intptr(MYNAME, 1, argc, argv);
1376     else
1377       scheme_wrong_contract(MYNAME, "exact-nonnegative-integer?", 1, argc, argv);
1378   }
1379 
1380   /* libffi doesn't seem to support array types, but we try to make
1381      libffi work anyway by making a structure type that is used when
1382      an array appears as a struct field. If the array size is 4 or
1383      less, or if the total size is SMALL_ARRAY_THRESHOLD bytes or
1384      less, then we make a full `elements' array, because the x86_64
1385      ABI always shifts to memory mode after 32 bytes and the AArch64
1386      ABI shifts after 64 bytes. */
1387 
1388   /* Allocate the new libffi type object, which is only provided to
1389      libffi as a type for a structure field.  When a FOREIGN_array
1390      type is used for a function argument or result, it is replaced
1391      with FOREIGN_pointer.  We put FFI_TYPE_STRUCT in
1392      libffi_type->type and make an elements array that contains
1393      a single instance of the element type... which seems to work
1394      ok so far.  */
1395   libffi_type = malloc(sizeof(ffi_type));
1396   size = mult_check_overflow(MYNAME, CTYPE_PRIMTYPE(base)->size, len);
1397   libffi_type->size      = size;
1398   libffi_type->alignment = CTYPE_PRIMTYPE(base)->alignment;
1399   libffi_type->type      = FFI_TYPE_STRUCT;
1400 
1401   if ((libffi_type->size <= SMALL_ARRAY_THRESHOLD) || (len <= 4)) {
1402     int i;
1403     elements = malloc((len + 1) * sizeof(ffi_type*));
1404     for (i = 0; i < len; i++) {
1405       elements[i] = CTYPE_PRIMTYPE(base);
1406     }
1407     elements[len] = NULL;
1408   } else {
1409     elements = malloc(2 * sizeof(ffi_type*));
1410     elements[0] = CTYPE_PRIMTYPE(base);
1411     elements[1] = NULL;
1412   }
1413   libffi_type->elements  = elements;
1414 
1415   basetype = scheme_make_vector(2, argv[0]);
1416   SCHEME_VEC_ELS(basetype)[1] = argv[1];
1417 
1418   type = (ctype_struct*)scheme_malloc_tagged(sizeof(ctype_struct));
1419   type->so.type = ctype_tag;
1420   type->basetype = (basetype);
1421   type->scheme_to_c = ((Scheme_Object*)libffi_type);
1422   type->c_to_scheme = ((Scheme_Object*)FOREIGN_array);
1423 
1424   scheme_register_finalizer(type, free_libffi_type, libffi_type, NULL, NULL);
1425 
1426   return (Scheme_Object*)type;
1427 }
1428 #undef MYNAME
1429 
1430 /*****************************************************************************/
1431 /* union types */
1432 
1433 static int all_float_types(GC_CAN_IGNORE ffi_type *libffi_type);
1434 
1435 /* (make-union-type type ...+) -> ctype */
1436 /* This creates a new primitive type that is a union. All unions
1437  * behave like structs. Marshaling to lists or whatever should
1438  * be done in Racket. */
1439 #define MYNAME "make-union-type"
foreign_make_union_type(int argc,Scheme_Object * argv[])1440 static Scheme_Object *foreign_make_union_type(int argc, Scheme_Object *argv[])
1441 {
1442   Scheme_Object *base, *basetype;
1443   GC_CAN_IGNORE ffi_type *libffi_type, **elements = NULL;
1444   ctype_struct *type;
1445   int i, align = 1, a, sz = 0, count = 0, float_kinds = 0, float_kind;
1446   int some_non_floats = 0;
1447 
1448   /* libffi doesn't support union types, so we try to make a
1449      reasonable approximation. The calling convention of a union type
1450      mostly likely depends on of the maximum size of all alternatives
1451      and whether it's floating-point or not. Synthesize a struct that
1452      is big enough and composed of only floats if the union
1453      alternative are only floats or integers otherwise. This is not
1454      guaranteed to be right, but it has a chance at working. */
1455 
1456   /* find max required alignment and size: */
1457   for (i = 0; i < argc; i++) {
1458     if (NULL == (base = get_ctype_base(argv[i]))) {
1459       free(elements);
1460       scheme_wrong_contract(MYNAME, "ctype?", i, argc, argv);
1461     }
1462     a = CTYPE_PRIMTYPE(base)->alignment;
1463     if (a > align) align = a;
1464     a = CTYPE_PRIMTYPE(base)->size;
1465     if (sz < a) sz = a;
1466 
1467     float_kind = all_float_types(CTYPE_PRIMTYPE(base));
1468     if (i == 0) float_kinds = float_kind;
1469     if (!float_kind || (float_kind != float_kinds))
1470       some_non_floats = 1;
1471   }
1472 
1473   if (!sz)
1474     scheme_signal_error("empty union");
1475 
1476   /* round size up to alignment: */
1477   if ((sz % align) != 0) {
1478     sz += (align - (sz % align));
1479   }
1480 
1481   /* Synthesize element list */
1482   while (!elements) {
1483     if (count)
1484       elements = malloc((count+1) * sizeof(ffi_type*));
1485     count = 0;
1486 
1487     if (some_non_floats) {
1488       /* build a struct out of integers */
1489       int remain_sz = sz;
1490       while (remain_sz >= sizeof(intptr_t)) {
1491         if (elements)
1492           elements[count] = &ffi_type_smzintptr;
1493         remain_sz -= sizeof(intptr_t);
1494         count++;
1495       }
1496       while (remain_sz >= sizeof(int)) {
1497         if (elements)
1498           elements[count] = &ffi_type_sint32;
1499         remain_sz -= sizeof(int);
1500         count++;
1501       }
1502       while (remain_sz >= sizeof(short)) {
1503         if (elements)
1504           elements[count] = &ffi_type_sint16;
1505         remain_sz -= sizeof(short);
1506         count++;
1507       }
1508       while (remain_sz) {
1509         if (elements)
1510           elements[count] = &ffi_type_sint8;
1511         remain_sz -= 1;
1512         count++;
1513       }
1514       /* remain_sz should be 0 at this point */
1515     } else {
1516       /* build a struct out of doubles and floats */
1517       int remain_sz = sz;
1518       while (remain_sz >= sizeof(double)) {
1519         if (elements)
1520           elements[count] = &ffi_type_double;
1521         remain_sz -= sizeof(double);
1522         count++;
1523       }
1524       while (remain_sz >= sizeof(float)) {
1525         if (elements)
1526           elements[count] = &ffi_type_float;
1527         remain_sz -= sizeof(float);
1528         count++;
1529       }
1530       /* remain_sz should be 0 at this point */
1531     }
1532   }
1533 
1534   elements[count] = NULL;
1535 
1536   /* Allocate the new libffi type object. */
1537   libffi_type = malloc(sizeof(ffi_type));
1538   libffi_type->size      = sz;
1539   libffi_type->alignment = align;
1540   libffi_type->type      = FFI_TYPE_STRUCT;
1541   libffi_type->elements  = elements;
1542 
1543   basetype = scheme_box(scheme_build_list(argc, argv));
1544 
1545   type = (ctype_struct*)scheme_malloc_tagged(sizeof(ctype_struct));
1546   type->so.type = ctype_tag;
1547   type->basetype = (basetype);
1548   type->scheme_to_c = ((Scheme_Object*)libffi_type);
1549   type->c_to_scheme = ((Scheme_Object*)FOREIGN_union);
1550 
1551   scheme_register_finalizer(type, free_libffi_type, libffi_type, NULL, NULL);
1552 
1553   return (Scheme_Object*)type;
1554 }
1555 #undef MYNAME
1556 
all_float_types_k(void)1557 static Scheme_Object *all_float_types_k(void)
1558 {
1559   Scheme_Thread *p = scheme_current_thread;
1560   int r;
1561   r = all_float_types((ffi_type *)p->ku.k.i1);
1562   return scheme_make_integer(r);
1563 }
1564 
1565 #if defined(__arm__) || defined(__thumb__) || defined(__aarch64__)
1566 /* Arm: uniform floats must be the same type */
1567 # define FLOAT_KIND_DOUBLE 1
1568 # define FLOAT_KIND_FLOAT  2
1569 # define FLOAT_KIND_EXT    3
1570 #else
1571 /* Other: different kinds of floats are treated the same */
1572 # define FLOAT_KIND_DOUBLE 1
1573 # define FLOAT_KIND_FLOAT  1
1574 # define FLOAT_KIND_EXT    1
1575 #endif
1576 
all_float_types(GC_CAN_IGNORE ffi_type * libffi_type)1577 static int all_float_types(GC_CAN_IGNORE ffi_type *libffi_type)
1578 {
1579   {
1580 # include "mzstkchk.h"
1581     {
1582       Scheme_Thread *p = scheme_current_thread;
1583       Scheme_Object *r;
1584       p->ku.k.i1 = (intptr_t)libffi_type;
1585       r = scheme_handle_stack_overflow(all_float_types_k);
1586       return SCHEME_INT_VAL(r);
1587     }
1588   }
1589 
1590   if (libffi_type == &ffi_type_double)
1591     return FLOAT_KIND_DOUBLE;
1592   if (libffi_type == &ffi_type_float)
1593     return FLOAT_KIND_FLOAT;
1594   if (libffi_type == &ffi_type_longdouble)
1595     return FLOAT_KIND_EXT;
1596 
1597   if (libffi_type->type == FFI_TYPE_STRUCT) {
1598     int i, kind = 0, k;
1599     for (i = 0; libffi_type->elements[i]; i++) {
1600       k = all_float_types(libffi_type->elements[i]);
1601       if (!k)
1602         return 0;
1603       if (!i)
1604         kind = k;
1605       else if (kind != k)
1606         return 0;
1607     }
1608     return kind;
1609   }
1610 
1611   return 0;
1612 }
1613 
1614 /*****************************************************************************/
1615 /* Callback type */
1616 
1617 /* ffi-callback structure definition */
1618 static Scheme_Type ffi_callback_tag;
1619 typedef struct ffi_callback_struct {
1620   Scheme_Object so;
1621   NON_GCBALE_PTR(void) callback;
1622   Scheme_Object* proc;
1623   Scheme_Object* itypes;
1624   Scheme_Object* otype;
1625   Scheme_Object* sync;
1626 } ffi_callback_struct;
1627 #define SCHEME_FFICALLBACKP(x) (SCHEME_TYPE(x)==ffi_callback_tag)
1628 #define MYNAME "ffi-callback?"
foreign_ffi_callback_p(int argc,Scheme_Object * argv[])1629 static Scheme_Object *foreign_ffi_callback_p(int argc, Scheme_Object *argv[])
1630 {
1631   return SCHEME_FFICALLBACKP(argv[0]) ? scheme_true : scheme_false;
1632 }
1633 #undef MYNAME
1634 /* 3m stuff for ffi_callback */
1635 #ifdef MZ_PRECISE_GC
1636 START_XFORM_SKIP;
ffi_callback_SIZE(void * p)1637 int ffi_callback_SIZE(void *p) {
1638   return gcBYTES_TO_WORDS(sizeof(ffi_callback_struct));
1639 }
ffi_callback_MARK(void * p)1640 int ffi_callback_MARK(void *p) {
1641   ffi_callback_struct *s = (ffi_callback_struct *)p;
1642   gcMARK(s->proc);
1643   gcMARK(s->itypes);
1644   gcMARK(s->otype);
1645   gcMARK(s->sync);
1646   return gcBYTES_TO_WORDS(sizeof(ffi_callback_struct));
1647 }
ffi_callback_FIXUP(void * p)1648 int ffi_callback_FIXUP(void *p) {
1649   ffi_callback_struct *s = (ffi_callback_struct *)p;
1650   gcFIXUP(s->proc);
1651   gcFIXUP(s->itypes);
1652   gcFIXUP(s->otype);
1653   gcFIXUP(s->sync);
1654   return gcBYTES_TO_WORDS(sizeof(ffi_callback_struct));
1655 }
1656 END_XFORM_SKIP;
1657 #endif   /* pointer to another ffi-callback for a curried callback */
1658 
1659 /* The sync field:
1660  *   NULL => non-atomic mode
1661  *   #t => atomic mode, no sync proc
1662  *   proc => non-atomic mode, sync proc
1663  *   (box proc) => atomic mode, sync proc
1664 */
1665 
1666 /*****************************************************************************/
1667 /* Pointer objects */
1668 /* use cpointer (with a NULL tag when creating), #f for NULL */
1669 
1670 #define SCHEME_FFIANYPTRP(x) \
1671   (SCHEME_FALSEP(x) || SCHEME_CPTRP(x) || SCHEME_FFIOBJP(x) || \
1672    SCHEME_BYTE_STRINGP(x) || SCHEME_FFICALLBACKP(x))
1673 #define SCHEME_FFIANYPTR_VAL(x) \
1674   (SCHEME_CPTRP(x) ? SCHEME_CPTR_VAL(x) : \
1675     (SCHEME_FALSEP(x) ? NULL : \
1676       (SCHEME_FFIOBJP(x) ? (((ffi_obj_struct*)x)->obj) : \
1677        (SCHEME_BYTE_STRINGP(x) ? SCHEME_BYTE_STR_VAL(x) : \
1678          (SCHEME_FFICALLBACKP(x) ? ((ffi_callback_struct *)x)->callback : \
1679           NULL)))))
1680 #define SCHEME_FFIANYPTR_OFFSET(x) \
1681   (SCHEME_CPTRP(x) ? SCHEME_CPTR_OFFSET(x) : 0)
1682 #define SCHEME_FFIANYPTR_OFFSETVAL(x) \
1683   W_OFFSET(SCHEME_FFIANYPTR_VAL(x), SCHEME_FFIANYPTR_OFFSET(x))
1684 
1685 #define SCHEME_CPOINTER_W_OFFSET_P(x) \
1686   (SCHEME_CPTRP(x) && SCHEME_CPTR_HAS_OFFSET(x))
1687 
1688 #define scheme_make_foreign_cpointer(x) \
1689   ((x==NULL)?scheme_false:scheme_make_cptr(x,NULL))
1690 
1691 #define scheme_make_foreign_offset_cpointer(x, delta) \
1692   ((delta == 0) ? scheme_make_foreign_cpointer(x) : scheme_make_offset_cptr(x,delta,NULL))
1693 
1694 #define scheme_make_foreign_external_cpointer(x) \
1695   ((x==NULL)?scheme_false:scheme_make_external_cptr(x,NULL))
1696 
1697 #define scheme_make_foreign_offset_external_cpointer(x, delta) \
1698   ((delta == 0) ? scheme_make_foreign_external_cpointer(x) : scheme_make_offset_external_cptr(x,delta,NULL))
1699 
check_cpointer_property(Scheme_Object * v)1700 static int check_cpointer_property(Scheme_Object *v)
1701 {
1702   if (SCHEME_CHAPERONE_STRUCTP(v)
1703       && scheme_struct_type_property_ref(scheme_cpointer_property, v))
1704     return 1;
1705   else
1706     return 0;
1707 }
1708 
unwrap_cpointer_property_slow(Scheme_Object * orig_v)1709 static Scheme_Object *unwrap_cpointer_property_slow(Scheme_Object *orig_v)
1710 {
1711   Scheme_Object *v = orig_v, *val;
1712   int must = 0;
1713 
1714   while (1) {
1715     if (SCHEME_CHAPERONE_STRUCTP(v)) {
1716       val = scheme_struct_type_property_ref(scheme_cpointer_property, v);
1717       if (val) {
1718         if (SCHEME_INTP(val))
1719           v = scheme_struct_ref(v, SCHEME_INT_VAL(val));
1720         else if (SCHEME_PROCP(val)) {
1721           Scheme_Object *a[1];
1722           a[0] = v;
1723           v = _scheme_apply(val, 1, a);
1724         } else
1725           v = val;
1726         must = 1;
1727       } else
1728         break;
1729     } else
1730       break;
1731   }
1732 
1733   if (must && !SCHEME_FFIANYPTRP(v)) {
1734     scheme_wrong_contract("prop:cpointer accessor", "cpointer?", 0, -1, &v);
1735     return NULL;
1736   }
1737 
1738   return v;
1739 }
1740 
unwrap_cpointer_property(Scheme_Object * v)1741 static Scheme_Object *unwrap_cpointer_property(Scheme_Object *v)
1742 {
1743   if (SCHEME_FFIANYPTRP(v))
1744     return v;
1745   else
1746     return unwrap_cpointer_property_slow(v);
1747 }
1748 
scheme_is_cpointer(Scheme_Object * cp)1749 int scheme_is_cpointer(Scheme_Object *cp) {
1750   return (SCHEME_FFIANYPTRP(cp) || check_cpointer_property(cp));
1751 }
1752 
1753 #define MYNAME "cpointer?"
foreign_cpointer_p(int argc,Scheme_Object * argv[])1754 static Scheme_Object *foreign_cpointer_p(int argc, Scheme_Object *argv[])
1755 {
1756   return (scheme_is_cpointer(argv[0])
1757           ? scheme_true
1758           : scheme_false);
1759 }
1760 #undef MYNAME
1761 
1762 #define MYNAME "cpointer-tag"
foreign_cpointer_tag(int argc,Scheme_Object * argv[])1763 static Scheme_Object *foreign_cpointer_tag(int argc, Scheme_Object *argv[])
1764 {
1765   Scheme_Object *tag = NULL;
1766   Scheme_Object *cp;
1767   cp = unwrap_cpointer_property(argv[0]);
1768   if (!SCHEME_FFIANYPTRP(cp))
1769     scheme_wrong_contract(MYNAME, "cpointer?", 0, argc, argv);
1770   if (SCHEME_CPTRP(cp)) tag = SCHEME_CPTR_TYPE(cp);
1771   return (tag == NULL) ? scheme_false : tag;
1772 }
1773 #undef MYNAME
1774 
scheme_cpointer_tag(Scheme_Object * ptr)1775 Scheme_Object *scheme_cpointer_tag(Scheme_Object *ptr)
1776 {
1777   Scheme_Object *a[1];
1778   a[0] = ptr;
1779   return foreign_cpointer_tag(1, a);
1780 }
1781 
1782 #define MYNAME "set-cpointer-tag!"
foreign_set_cpointer_tag_bang(int argc,Scheme_Object * argv[])1783 static Scheme_Object *foreign_set_cpointer_tag_bang(int argc, Scheme_Object *argv[])
1784 {
1785   Scheme_Object *cp;
1786   cp = unwrap_cpointer_property(argv[0]);
1787   if (!SCHEME_CPTRP(cp))
1788     scheme_wrong_contract(MYNAME, "proper-cpointer?", 0, argc, argv);
1789   SCHEME_CPTR_TYPE(cp) = argv[1];
1790   return scheme_void;
1791 }
1792 #undef MYNAME
1793 
scheme_set_cpointer_tag(Scheme_Object * ptr,Scheme_Object * val)1794 void scheme_set_cpointer_tag(Scheme_Object *ptr, Scheme_Object *val)
1795 {
1796   Scheme_Object *a[2];
1797   a[0] = ptr;
1798   a[1] = val;
1799   (void)foreign_set_cpointer_tag_bang(2, a);
1800 }
1801 
1802 #define MYNAME "cpointer-gcable?"
foreign_cpointer_gcable_p(int argc,Scheme_Object * argv[])1803 static Scheme_Object *foreign_cpointer_gcable_p(int argc, Scheme_Object *argv[])
1804 {
1805   Scheme_Object *cp;
1806   cp = unwrap_cpointer_property(argv[0]);
1807   if (SCHEME_CPTRP(cp)) {
1808     return ((SCHEME_CPTR_FLAGS(cp) & 0x1)
1809             ? scheme_false
1810             : scheme_true);
1811   } else if (SCHEME_FALSEP(cp)
1812              || SCHEME_FFIOBJP(cp)
1813              || SCHEME_FFICALLBACKP(cp))
1814     return scheme_false;
1815   else if (SCHEME_BYTE_STRINGP(cp))
1816     return scheme_true;
1817   else {
1818     scheme_wrong_contract(MYNAME, "cpointer?", 0, argc, argv);
1819     return NULL;
1820   }
1821 }
1822 #undef MYNAME
1823 
scheme_extract_pointer(Scheme_Object * v)1824 void *scheme_extract_pointer(Scheme_Object *v) {
1825   return SCHEME_FFIANYPTR_OFFSETVAL(v);
1826 }
1827 
1828 /*****************************************************************************/
1829 /* Racket<-->C conversions */
1830 
1831 /* On big endian machines we need to know whether we're pulling a value from an
1832  * argument location where it always takes a whole word or straight from a
1833  * memory location -- deal with it via a C2SCHEME macro wrapper that is used
1834  * for both the function definition and calls */
1835 #ifdef SCHEME_BIG_ENDIAN
1836 #define C2SCHEME(ap,typ,src,delta,argsloc,gcsrc) c_to_scheme(ap,typ,src,delta,argsloc,gcsrc)
1837 #define REF_CTYPE(ctype) (((sizeof(ctype)<sizeof(intptr_t)) && args_loc) \
1838   ? ((ctype)(((intptr_t*)W_OFFSET(src,delta))[0])) \
1839   : (((ctype *)W_OFFSET(src,delta))[0]))
1840 #else
1841 #define C2SCHEME(ap,typ,src,delta,argsloc,gcsrc) c_to_scheme(ap,typ,src,delta,gcsrc)
1842 #define REF_CTYPE(ctype) (((ctype *)W_OFFSET(src,delta))[0])
1843 #endif
1844 
C2SCHEME(Scheme_Object * already_ptr,Scheme_Object * type,void * src,intptr_t delta,int args_loc,int gcsrc)1845 static Scheme_Object *C2SCHEME(Scheme_Object *already_ptr, Scheme_Object *type, void *src,
1846                                intptr_t delta, int args_loc, int gcsrc)
1847 {
1848   Scheme_Object *res;
1849   if (!SCHEME_CTYPEP(type))
1850     scheme_wrong_contract("C->Racket", "ctype?", 0, 1, &type);
1851   if (CTYPE_USERP(type)) {
1852     res = C2SCHEME(already_ptr, CTYPE_BASETYPE(type), src, delta, args_loc, gcsrc);
1853     if (SCHEME_FALSEP(CTYPE_USER_C2S(type)))
1854       return res;
1855     else
1856       return _scheme_apply(CTYPE_USER_C2S(type), 1, (Scheme_Object**)(&res));
1857   } else if (CTYPE_PRIMLABEL(type) == FOREIGN_fpointer) {
1858     if (already_ptr) return already_ptr;
1859     return scheme_make_foreign_external_cpointer(*(void **)W_OFFSET(src, delta));
1860   } else switch (CTYPE_PRIMLABEL(type)) {
1861     case FOREIGN_void: return scheme_void;
1862     case FOREIGN_int8: return scheme_make_integer(REF_CTYPE(Tsint8));
1863     case FOREIGN_uint8: return scheme_make_integer(REF_CTYPE(Tuint8));
1864     case FOREIGN_int16: return scheme_make_integer(REF_CTYPE(Tsint16));
1865     case FOREIGN_uint16: return scheme_make_integer(REF_CTYPE(Tuint16));
1866     case FOREIGN_int32: return scheme_make_realinteger_value(REF_CTYPE(Tsint32));
1867     case FOREIGN_uint32: return scheme_make_realinteger_value_from_unsigned(REF_CTYPE(Tuint32));
1868     case FOREIGN_int64: return scheme_make_integer_value_from_long_long(REF_CTYPE(Tsint64));
1869     case FOREIGN_uint64: return scheme_make_integer_value_from_unsigned_long_long(REF_CTYPE(Tuint64));
1870     case FOREIGN_fixint: return scheme_make_integer(REF_CTYPE(Tsint32));
1871     case FOREIGN_ufixint: return scheme_make_integer_from_unsigned(REF_CTYPE(Tuint32));
1872     case FOREIGN_fixnum: return scheme_make_integer(REF_CTYPE(intptr_t));
1873     case FOREIGN_ufixnum: return scheme_make_integer_from_unsigned(REF_CTYPE(uintptr_t));
1874     case FOREIGN_float: return scheme_make_double(REF_CTYPE(float));
1875     case FOREIGN_double: return scheme_make_double(REF_CTYPE(double));
1876     case FOREIGN_longdouble: return scheme_make_maybe_long_double(REF_CTYPE(mz_long_double));
1877     case FOREIGN_doubleS: return scheme_make_double(REF_CTYPE(double));
1878     case FOREIGN_bool: return (REF_CTYPE(int)?scheme_true:scheme_false);
1879     case FOREIGN_stdbool: return (REF_CTYPE(stdbool)?scheme_true:scheme_false);
1880     case FOREIGN_string_ucs_4: return scheme_make_char_string_without_copying(REF_CTYPE(mzchar*));
1881     case FOREIGN_string_utf_16: return utf16_pointer_to_ucs4_string(REF_CTYPE(unsigned short*));
1882     case FOREIGN_bytes: return (REF_CTYPE(char*)==NULL)?scheme_false:scheme_make_byte_string_without_copying(REF_CTYPE(char*));
1883     case FOREIGN_path: return (REF_CTYPE(char*)==NULL)?scheme_false:scheme_make_path_without_copying(REF_CTYPE(char*));
1884     case FOREIGN_symbol: return scheme_intern_symbol(REF_CTYPE(char*));
1885     case FOREIGN_pointer: return scheme_make_foreign_external_cpointer(REF_CTYPE(void*));
1886     case FOREIGN_gcpointer: return scheme_make_foreign_cpointer(REF_CTYPE(void*));
1887     case FOREIGN_scheme: return REF_CTYPE(Scheme_Object*);
1888     case FOREIGN_fpointer: return (REF_CTYPE(void*));
1889     case FOREIGN_struct:
1890     case FOREIGN_array:
1891     case FOREIGN_union:
1892       if (gcsrc)
1893         return scheme_make_foreign_offset_cpointer(src, delta);
1894       else
1895         return scheme_make_foreign_offset_external_cpointer(src, delta);
1896     default: scheme_signal_error("corrupt foreign type: %V", type);
1897   }
1898   return NULL; /* hush the compiler */
1899 }
1900 #undef REF_CTYPE
1901 
wrong_value(const char * who,const char * type,Scheme_Object * val)1902 static void *wrong_value(const char *who, const char *type, Scheme_Object *val)
1903 {
1904   scheme_contract_error(who,
1905                         "given value does not fit primitive C type",
1906                         "C type", 0, type,
1907                         "given value", 1, val,
1908                         NULL);
1909   return NULL;
1910 }
1911 
1912 /* On big endian machines we need to know whether we're pulling a value from an
1913  * argument location where it always takes a whole word or straight from a
1914  * memory location -- deal with it as above, via a SCHEME2C macro wrapper that
1915  * is used for both the function definition and calls, but the actual code in
1916  * the function is different: in the relevant cases zero an int and offset the
1917  * ptr */
1918 
1919 /* Usually writes the C object to dst and returns NULL.  When basetype_p is not
1920  * NULL, then any pointer value (any pointer or a struct or array) is returned, and the
1921  * basetype_p is set to the corresponding number tag.  If basetype_p is NULL,
1922  * then a struct or array value will be *copied* into dst. */
SCHEME2C(const char * who,Scheme_Object * type,void * dst,intptr_t delta,Scheme_Object * val,GC_CAN_IGNORE intptr_t * basetype_p,GC_CAN_IGNORE intptr_t * _offset,int ret_loc)1923 static void* SCHEME2C(const char *who,
1924                       Scheme_Object *type, void *dst, intptr_t delta,
1925                       Scheme_Object *val, GC_CAN_IGNORE intptr_t *basetype_p, GC_CAN_IGNORE intptr_t *_offset,
1926                       int ret_loc)
1927 {
1928   /* redundant check:
1929      if (!SCHEME_CTYPEP(type))
1930        scheme_wrong_contract(who, "ctype?", 0, 1, &type); */
1931   while (CTYPE_USERP(type)) {
1932     GC_CAN_IGNORE Scheme_Object *f = CTYPE_USER_S2C(type);
1933     if (!SCHEME_FALSEP(f)) {
1934       if (SAME_TYPE(SCHEME_TYPE(f), scheme_native_closure_type))
1935         val = _scheme_apply_native(f, 1, (Scheme_Object**)(&val));
1936       else
1937         val = _scheme_apply(f, 1, (Scheme_Object**)(&val));
1938     }
1939     type = CTYPE_BASETYPE(type);
1940   }
1941   if (CTYPE_PRIMLABEL(type) == FOREIGN_fpointer) {
1942     val = unwrap_cpointer_property(val);
1943     /* No need for the SET_CTYPE trick for pointers. */
1944     if (SCHEME_FFICALLBACKP(val))
1945       ((void**)W_OFFSET(dst,delta))[0] = ((ffi_callback_struct*)val)->callback;
1946     else if (SCHEME_CPTRP(val))
1947       ((void**)W_OFFSET(dst,delta))[0] = SCHEME_CPTR_VAL(val);
1948     else if (SCHEME_FFIOBJP(val))
1949       ((void**)W_OFFSET(dst,delta))[0] = ((ffi_obj_struct*)val)->obj;
1950     else if (SCHEME_FALSEP(val))
1951       ((void**)W_OFFSET(dst,delta))[0] = NULL;
1952     else /* ((void**)W_OFFSET(dst,delta))[0] = val; */
1953       return wrong_value(who, "_fpointer", val);
1954   } else switch (CTYPE_PRIMLABEL(type)) {
1955     case FOREIGN_void:
1956       if (!ret_loc) return wrong_value(who, "_void", val);;
1957       break;
1958     case FOREIGN_int8:
1959 #     ifdef SCHEME_BIG_ENDIAN
1960       if (sizeof(Tsint8)<sizeof(intptr_t) && ret_loc) {
1961         ((int*)W_OFFSET(dst,delta))[0] = 0;
1962         delta += (sizeof(intptr_t)-sizeof(Tsint8));
1963       }
1964 #     endif /* SCHEME_BIG_ENDIAN */
1965 #     ifdef FFI_CALLBACK_NEED_INT_CLEAR
1966       if (sizeof(Tsint8)<sizeof(intptr_t) && ret_loc) {
1967         ((int*)W_OFFSET(dst,delta))[0] = 0;
1968       }
1969 #     endif /* FFI_CALLBACK_NEED_INT_CLEAR */
1970       if (!(get_byte_val(val,&(((Tsint8*)W_OFFSET(dst,delta))[0])))) return wrong_value(who, "_int8", val);;
1971       return NULL;
1972     case FOREIGN_uint8:
1973 #     ifdef SCHEME_BIG_ENDIAN
1974       if (sizeof(Tuint8)<sizeof(intptr_t) && ret_loc) {
1975         ((int*)W_OFFSET(dst,delta))[0] = 0;
1976         delta += (sizeof(intptr_t)-sizeof(Tuint8));
1977       }
1978 #     endif /* SCHEME_BIG_ENDIAN */
1979 #     ifdef FFI_CALLBACK_NEED_INT_CLEAR
1980       if (sizeof(Tuint8)<sizeof(intptr_t) && ret_loc) {
1981         ((int*)W_OFFSET(dst,delta))[0] = 0;
1982       }
1983 #     endif /* FFI_CALLBACK_NEED_INT_CLEAR */
1984       if (!(get_ubyte_val(val,&(((Tuint8*)W_OFFSET(dst,delta))[0])))) return wrong_value(who, "_uint8", val);;
1985       return NULL;
1986     case FOREIGN_int16:
1987 #     ifdef SCHEME_BIG_ENDIAN
1988       if (sizeof(Tsint16)<sizeof(intptr_t) && ret_loc) {
1989         ((int*)W_OFFSET(dst,delta))[0] = 0;
1990         delta += (sizeof(intptr_t)-sizeof(Tsint16));
1991       }
1992 #     endif /* SCHEME_BIG_ENDIAN */
1993 #     ifdef FFI_CALLBACK_NEED_INT_CLEAR
1994       if (sizeof(Tsint16)<sizeof(intptr_t) && ret_loc) {
1995         ((int*)W_OFFSET(dst,delta))[0] = 0;
1996       }
1997 #     endif /* FFI_CALLBACK_NEED_INT_CLEAR */
1998       if (!(get_short_val(val,&(((Tsint16*)W_OFFSET(dst,delta))[0])))) return wrong_value(who, "_int16", val);;
1999       return NULL;
2000     case FOREIGN_uint16:
2001 #     ifdef SCHEME_BIG_ENDIAN
2002       if (sizeof(Tuint16)<sizeof(intptr_t) && ret_loc) {
2003         ((int*)W_OFFSET(dst,delta))[0] = 0;
2004         delta += (sizeof(intptr_t)-sizeof(Tuint16));
2005       }
2006 #     endif /* SCHEME_BIG_ENDIAN */
2007 #     ifdef FFI_CALLBACK_NEED_INT_CLEAR
2008       if (sizeof(Tuint16)<sizeof(intptr_t) && ret_loc) {
2009         ((int*)W_OFFSET(dst,delta))[0] = 0;
2010       }
2011 #     endif /* FFI_CALLBACK_NEED_INT_CLEAR */
2012       if (!(get_ushort_val(val,&(((Tuint16*)W_OFFSET(dst,delta))[0])))) return wrong_value(who, "_uint16", val);;
2013       return NULL;
2014     case FOREIGN_int32:
2015 #     ifdef SCHEME_BIG_ENDIAN
2016       if (sizeof(Tsint32)<sizeof(intptr_t) && ret_loc) {
2017         ((int*)W_OFFSET(dst,delta))[0] = 0;
2018         delta += (sizeof(intptr_t)-sizeof(Tsint32));
2019       }
2020 #     endif /* SCHEME_BIG_ENDIAN */
2021 #     ifdef FFI_CALLBACK_NEED_INT_CLEAR
2022       if (sizeof(Tsint32)<sizeof(intptr_t) && ret_loc) {
2023         ((int*)W_OFFSET(dst,delta))[0] = 0;
2024       }
2025 #     endif /* FFI_CALLBACK_NEED_INT_CLEAR */
2026       if (!(scheme_get_realint_val(val,&(((Tsint32*)W_OFFSET(dst,delta))[0])))) return wrong_value(who, "_int32", val);;
2027       return NULL;
2028     case FOREIGN_uint32:
2029 #     ifdef SCHEME_BIG_ENDIAN
2030       if (sizeof(Tuint32)<sizeof(intptr_t) && ret_loc) {
2031         ((int*)W_OFFSET(dst,delta))[0] = 0;
2032         delta += (sizeof(intptr_t)-sizeof(Tuint32));
2033       }
2034 #     endif /* SCHEME_BIG_ENDIAN */
2035 #     ifdef FFI_CALLBACK_NEED_INT_CLEAR
2036       if (sizeof(Tuint32)<sizeof(intptr_t) && ret_loc) {
2037         ((int*)W_OFFSET(dst,delta))[0] = 0;
2038       }
2039 #     endif /* FFI_CALLBACK_NEED_INT_CLEAR */
2040       if (!(scheme_get_unsigned_realint_val(val,&(((Tuint32*)W_OFFSET(dst,delta))[0])))) return wrong_value(who, "_uint32", val);;
2041       return NULL;
2042     case FOREIGN_int64:
2043 #     ifdef SCHEME_BIG_ENDIAN
2044       if (sizeof(Tsint64)<sizeof(intptr_t) && ret_loc) {
2045         ((int*)W_OFFSET(dst,delta))[0] = 0;
2046         delta += (sizeof(intptr_t)-sizeof(Tsint64));
2047       }
2048 #     endif /* SCHEME_BIG_ENDIAN */
2049 #     ifdef FFI_CALLBACK_NEED_INT_CLEAR
2050       if (sizeof(Tsint64)<sizeof(intptr_t) && ret_loc) {
2051         ((int*)W_OFFSET(dst,delta))[0] = 0;
2052       }
2053 #     endif /* FFI_CALLBACK_NEED_INT_CLEAR */
2054       if (!(scheme_get_long_long_val(val,&(((Tsint64*)W_OFFSET(dst,delta))[0])))) return wrong_value(who, "_int64", val);;
2055       return NULL;
2056     case FOREIGN_uint64:
2057 #     ifdef SCHEME_BIG_ENDIAN
2058       if (sizeof(Tuint64)<sizeof(intptr_t) && ret_loc) {
2059         ((int*)W_OFFSET(dst,delta))[0] = 0;
2060         delta += (sizeof(intptr_t)-sizeof(Tuint64));
2061       }
2062 #     endif /* SCHEME_BIG_ENDIAN */
2063 #     ifdef FFI_CALLBACK_NEED_INT_CLEAR
2064       if (sizeof(Tuint64)<sizeof(intptr_t) && ret_loc) {
2065         ((int*)W_OFFSET(dst,delta))[0] = 0;
2066       }
2067 #     endif /* FFI_CALLBACK_NEED_INT_CLEAR */
2068       if (!(scheme_get_unsigned_long_long_val(val,&(((Tuint64*)W_OFFSET(dst,delta))[0])))) return wrong_value(who, "_uint64", val);;
2069       return NULL;
2070     case FOREIGN_fixint:
2071 #     ifdef SCHEME_BIG_ENDIAN
2072       if (sizeof(Tsint32)<sizeof(intptr_t) && ret_loc) {
2073         ((int*)W_OFFSET(dst,delta))[0] = 0;
2074         delta += (sizeof(intptr_t)-sizeof(Tsint32));
2075       }
2076 #     endif /* SCHEME_BIG_ENDIAN */
2077 #     ifdef FFI_CALLBACK_NEED_INT_CLEAR
2078       if (sizeof(Tsint32)<sizeof(intptr_t) && ret_loc) {
2079         ((int*)W_OFFSET(dst,delta))[0] = 0;
2080       }
2081 #     endif /* FFI_CALLBACK_NEED_INT_CLEAR */
2082 
2083       if (SCHEME_INTP(val)) {
2084         Tsint32 tmp;
2085         tmp = MZ_TYPE_CAST(Tsint32, SCHEME_INT_VAL(val));
2086         (((Tsint32*)W_OFFSET(dst,delta))[0]) = tmp; return NULL;
2087       } else {
2088         return wrong_value(who, "_fixint", val);;
2089         return NULL; /* hush the compiler */
2090       }
2091     case FOREIGN_ufixint:
2092 #     ifdef SCHEME_BIG_ENDIAN
2093       if (sizeof(Tuint32)<sizeof(intptr_t) && ret_loc) {
2094         ((int*)W_OFFSET(dst,delta))[0] = 0;
2095         delta += (sizeof(intptr_t)-sizeof(Tuint32));
2096       }
2097 #     endif /* SCHEME_BIG_ENDIAN */
2098 #     ifdef FFI_CALLBACK_NEED_INT_CLEAR
2099       if (sizeof(Tuint32)<sizeof(intptr_t) && ret_loc) {
2100         ((int*)W_OFFSET(dst,delta))[0] = 0;
2101       }
2102 #     endif /* FFI_CALLBACK_NEED_INT_CLEAR */
2103 
2104       if (SCHEME_INTP(val)) {
2105         Tuint32 tmp;
2106         tmp = MZ_TYPE_CAST(Tuint32, SCHEME_UINT_VAL(val));
2107         (((Tuint32*)W_OFFSET(dst,delta))[0]) = tmp; return NULL;
2108       } else {
2109         return wrong_value(who, "_ufixint", val);;
2110         return NULL; /* hush the compiler */
2111       }
2112     case FOREIGN_fixnum:
2113 #     ifdef SCHEME_BIG_ENDIAN
2114       if (sizeof(intptr_t)<sizeof(intptr_t) && ret_loc) {
2115         ((int*)W_OFFSET(dst,delta))[0] = 0;
2116         delta += (sizeof(intptr_t)-sizeof(intptr_t));
2117       }
2118 #     endif /* SCHEME_BIG_ENDIAN */
2119 #     ifdef FFI_CALLBACK_NEED_INT_CLEAR
2120       if (sizeof(intptr_t)<sizeof(intptr_t) && ret_loc) {
2121         ((int*)W_OFFSET(dst,delta))[0] = 0;
2122       }
2123 #     endif /* FFI_CALLBACK_NEED_INT_CLEAR */
2124 
2125       if (SCHEME_INTP(val)) {
2126         intptr_t tmp;
2127         tmp = MZ_TYPE_CAST(intptr_t, SCHEME_INT_VAL(val));
2128         (((intptr_t*)W_OFFSET(dst,delta))[0]) = tmp; return NULL;
2129       } else {
2130         return wrong_value(who, "_fixnum", val);;
2131         return NULL; /* hush the compiler */
2132       }
2133     case FOREIGN_ufixnum:
2134 #     ifdef SCHEME_BIG_ENDIAN
2135       if (sizeof(uintptr_t)<sizeof(intptr_t) && ret_loc) {
2136         ((int*)W_OFFSET(dst,delta))[0] = 0;
2137         delta += (sizeof(intptr_t)-sizeof(uintptr_t));
2138       }
2139 #     endif /* SCHEME_BIG_ENDIAN */
2140 #     ifdef FFI_CALLBACK_NEED_INT_CLEAR
2141       if (sizeof(uintptr_t)<sizeof(intptr_t) && ret_loc) {
2142         ((int*)W_OFFSET(dst,delta))[0] = 0;
2143       }
2144 #     endif /* FFI_CALLBACK_NEED_INT_CLEAR */
2145 
2146       if (SCHEME_INTP(val)) {
2147         uintptr_t tmp;
2148         tmp = MZ_TYPE_CAST(uintptr_t, SCHEME_UINT_VAL(val));
2149         (((uintptr_t*)W_OFFSET(dst,delta))[0]) = tmp; return NULL;
2150       } else {
2151         return wrong_value(who, "_ufixnum", val);;
2152         return NULL; /* hush the compiler */
2153       }
2154     case FOREIGN_float:
2155 #     ifdef SCHEME_BIG_ENDIAN
2156       if (sizeof(float)<sizeof(intptr_t) && ret_loc) {
2157         ((int*)W_OFFSET(dst,delta))[0] = 0;
2158         delta += (sizeof(intptr_t)-sizeof(float));
2159       }
2160 #     endif /* SCHEME_BIG_ENDIAN */
2161 #     ifdef FFI_CALLBACK_NEED_INT_CLEAR
2162       if (sizeof(float)<sizeof(intptr_t) && ret_loc) {
2163         ((int*)W_OFFSET(dst,delta))[0] = 0;
2164       }
2165 #     endif /* FFI_CALLBACK_NEED_INT_CLEAR */
2166 
2167       if (SCHEME_FLOATP(val)) {
2168         float tmp;
2169         tmp = MZ_TYPE_CAST(float, SCHEME_FLOAT_VAL(val));
2170         (((float*)W_OFFSET(dst,delta))[0]) = tmp; return NULL;
2171       } else {
2172         return wrong_value(who, "_float", val);;
2173         return NULL; /* hush the compiler */
2174       }
2175     case FOREIGN_double:
2176 #     ifdef SCHEME_BIG_ENDIAN
2177       if (sizeof(double)<sizeof(intptr_t) && ret_loc) {
2178         ((int*)W_OFFSET(dst,delta))[0] = 0;
2179         delta += (sizeof(intptr_t)-sizeof(double));
2180       }
2181 #     endif /* SCHEME_BIG_ENDIAN */
2182 #     ifdef FFI_CALLBACK_NEED_INT_CLEAR
2183       if (sizeof(double)<sizeof(intptr_t) && ret_loc) {
2184         ((int*)W_OFFSET(dst,delta))[0] = 0;
2185       }
2186 #     endif /* FFI_CALLBACK_NEED_INT_CLEAR */
2187 
2188       if (SCHEME_FLOATP(val)) {
2189         double tmp;
2190         tmp = MZ_TYPE_CAST(double, SCHEME_FLOAT_VAL(val));
2191         (((double*)W_OFFSET(dst,delta))[0]) = tmp; return NULL;
2192       } else {
2193         return wrong_value(who, "_double", val);;
2194         return NULL; /* hush the compiler */
2195       }
2196     case FOREIGN_longdouble:
2197 #     ifdef SCHEME_BIG_ENDIAN
2198       if (sizeof(mz_long_double)<sizeof(intptr_t) && ret_loc) {
2199         ((int*)W_OFFSET(dst,delta))[0] = 0;
2200         delta += (sizeof(intptr_t)-sizeof(mz_long_double));
2201       }
2202 #     endif /* SCHEME_BIG_ENDIAN */
2203 #     ifdef FFI_CALLBACK_NEED_INT_CLEAR
2204       if (sizeof(mz_long_double)<sizeof(intptr_t) && ret_loc) {
2205         ((int*)W_OFFSET(dst,delta))[0] = 0;
2206       }
2207 #     endif /* FFI_CALLBACK_NEED_INT_CLEAR */
2208 
2209       if (SCHEME_LONG_DBLP(val)) {
2210         mz_long_double tmp;
2211         tmp = MZ_NO_TYPE_CAST(mz_long_double, SCHEME_MAYBE_LONG_DBL_VAL(val));
2212         (((mz_long_double*)W_OFFSET(dst,delta))[0]) = tmp; return NULL;
2213       } else {
2214         return wrong_value(who, "_longdouble", val);;
2215         return NULL; /* hush the compiler */
2216       }
2217     case FOREIGN_doubleS:
2218 #     ifdef SCHEME_BIG_ENDIAN
2219       if (sizeof(double)<sizeof(intptr_t) && ret_loc) {
2220         ((int*)W_OFFSET(dst,delta))[0] = 0;
2221         delta += (sizeof(intptr_t)-sizeof(double));
2222       }
2223 #     endif /* SCHEME_BIG_ENDIAN */
2224 #     ifdef FFI_CALLBACK_NEED_INT_CLEAR
2225       if (sizeof(double)<sizeof(intptr_t) && ret_loc) {
2226         ((int*)W_OFFSET(dst,delta))[0] = 0;
2227       }
2228 #     endif /* FFI_CALLBACK_NEED_INT_CLEAR */
2229 
2230       if (SCHEME_REALP(val)) {
2231         double tmp;
2232         tmp = MZ_TYPE_CAST(double, scheme_real_to_double(val));
2233         (((double*)W_OFFSET(dst,delta))[0]) = tmp; return NULL;
2234       } else {
2235         return wrong_value(who, "_double*", val);;
2236         return NULL; /* hush the compiler */
2237       }
2238     case FOREIGN_bool:
2239 #     ifdef SCHEME_BIG_ENDIAN
2240       if (sizeof(int)<sizeof(intptr_t) && ret_loc) {
2241         ((int*)W_OFFSET(dst,delta))[0] = 0;
2242         delta += (sizeof(intptr_t)-sizeof(int));
2243       }
2244 #     endif /* SCHEME_BIG_ENDIAN */
2245 #     ifdef FFI_CALLBACK_NEED_INT_CLEAR
2246       if (sizeof(int)<sizeof(intptr_t) && ret_loc) {
2247         ((int*)W_OFFSET(dst,delta))[0] = 0;
2248       }
2249 #     endif /* FFI_CALLBACK_NEED_INT_CLEAR */
2250 
2251       if (1) {
2252         int tmp;
2253         tmp = MZ_TYPE_CAST(int, SCHEME_TRUEP(val));
2254         (((int*)W_OFFSET(dst,delta))[0]) = tmp; return NULL;
2255       } else {
2256         return wrong_value(who, "_bool", val);;
2257         return NULL; /* hush the compiler */
2258       }
2259     case FOREIGN_stdbool:
2260 #     ifdef SCHEME_BIG_ENDIAN
2261       if (sizeof(stdbool)<sizeof(intptr_t) && ret_loc) {
2262         ((int*)W_OFFSET(dst,delta))[0] = 0;
2263         delta += (sizeof(intptr_t)-sizeof(stdbool));
2264       }
2265 #     endif /* SCHEME_BIG_ENDIAN */
2266 #     ifdef FFI_CALLBACK_NEED_INT_CLEAR
2267       if (sizeof(stdbool)<sizeof(intptr_t) && ret_loc) {
2268         ((int*)W_OFFSET(dst,delta))[0] = 0;
2269       }
2270 #     endif /* FFI_CALLBACK_NEED_INT_CLEAR */
2271 
2272       if (1) {
2273         stdbool tmp;
2274         tmp = MZ_TYPE_CAST(stdbool, SCHEME_TRUEP(val));
2275         (((stdbool*)W_OFFSET(dst,delta))[0]) = tmp; return NULL;
2276       } else {
2277         return wrong_value(who, "_stdbool", val);;
2278         return NULL; /* hush the compiler */
2279       }
2280     case FOREIGN_string_ucs_4:
2281 #     ifdef SCHEME_BIG_ENDIAN
2282       if (sizeof(mzchar*)<sizeof(intptr_t) && ret_loc) {
2283         ((int*)W_OFFSET(dst,delta))[0] = 0;
2284         delta += (sizeof(intptr_t)-sizeof(mzchar*));
2285       }
2286 #     endif /* SCHEME_BIG_ENDIAN */
2287 #     ifdef FFI_CALLBACK_NEED_INT_CLEAR
2288       if (sizeof(mzchar*)<sizeof(intptr_t) && ret_loc) {
2289         ((int*)W_OFFSET(dst,delta))[0] = 0;
2290       }
2291 #     endif /* FFI_CALLBACK_NEED_INT_CLEAR */
2292 
2293       if (SCHEME_FALSEP_OR_CHAR_STRINGP(val)) {
2294         mzchar* tmp;
2295         tmp = MZ_TYPE_CAST(mzchar*, ucs4_string_or_null_to_ucs4_pointer(val));
2296         if (basetype_p == NULL || tmp == NULL || 0) {
2297           (((mzchar**)W_OFFSET(dst,delta))[0]) = tmp;
2298           return NULL;
2299         } else {
2300           *basetype_p = FOREIGN_string_ucs_4;
2301           return tmp;
2302         }
2303       } else {
2304         return wrong_value(who, "_string/ucs-4", val);;
2305         return NULL; /* hush the compiler */
2306       }
2307     case FOREIGN_string_utf_16:
2308 #     ifdef SCHEME_BIG_ENDIAN
2309       if (sizeof(unsigned short*)<sizeof(intptr_t) && ret_loc) {
2310         ((int*)W_OFFSET(dst,delta))[0] = 0;
2311         delta += (sizeof(intptr_t)-sizeof(unsigned short*));
2312       }
2313 #     endif /* SCHEME_BIG_ENDIAN */
2314 #     ifdef FFI_CALLBACK_NEED_INT_CLEAR
2315       if (sizeof(unsigned short*)<sizeof(intptr_t) && ret_loc) {
2316         ((int*)W_OFFSET(dst,delta))[0] = 0;
2317       }
2318 #     endif /* FFI_CALLBACK_NEED_INT_CLEAR */
2319 
2320       if (SCHEME_FALSEP_OR_CHAR_STRINGP(val)) {
2321         unsigned short* tmp;
2322         tmp = MZ_TYPE_CAST(unsigned short*, ucs4_string_or_null_to_utf16_pointer(val));
2323         if (basetype_p == NULL || tmp == NULL || 0) {
2324           (((unsigned short**)W_OFFSET(dst,delta))[0]) = tmp;
2325           return NULL;
2326         } else {
2327           *basetype_p = FOREIGN_string_utf_16;
2328           return tmp;
2329         }
2330       } else {
2331         return wrong_value(who, "_string/utf-16", val);;
2332         return NULL; /* hush the compiler */
2333       }
2334     case FOREIGN_bytes:
2335 #     ifdef SCHEME_BIG_ENDIAN
2336       if (sizeof(char*)<sizeof(intptr_t) && ret_loc) {
2337         ((int*)W_OFFSET(dst,delta))[0] = 0;
2338         delta += (sizeof(intptr_t)-sizeof(char*));
2339       }
2340 #     endif /* SCHEME_BIG_ENDIAN */
2341 #     ifdef FFI_CALLBACK_NEED_INT_CLEAR
2342       if (sizeof(char*)<sizeof(intptr_t) && ret_loc) {
2343         ((int*)W_OFFSET(dst,delta))[0] = 0;
2344       }
2345 #     endif /* FFI_CALLBACK_NEED_INT_CLEAR */
2346 
2347       if (SCHEME_FALSEP(val)||SCHEME_BYTE_STRINGP(val)) {
2348         char* tmp;
2349         tmp = MZ_TYPE_CAST(char*, SCHEME_FALSEP(val)?NULL:SCHEME_BYTE_STR_VAL(val));
2350         if (basetype_p == NULL || tmp == NULL || 0) {
2351           (((char**)W_OFFSET(dst,delta))[0]) = tmp;
2352           return NULL;
2353         } else {
2354           *basetype_p = FOREIGN_bytes;
2355           return tmp;
2356         }
2357       } else {
2358         return wrong_value(who, "_bytes", val);;
2359         return NULL; /* hush the compiler */
2360       }
2361     case FOREIGN_path:
2362 #     ifdef SCHEME_BIG_ENDIAN
2363       if (sizeof(char*)<sizeof(intptr_t) && ret_loc) {
2364         ((int*)W_OFFSET(dst,delta))[0] = 0;
2365         delta += (sizeof(intptr_t)-sizeof(char*));
2366       }
2367 #     endif /* SCHEME_BIG_ENDIAN */
2368 #     ifdef FFI_CALLBACK_NEED_INT_CLEAR
2369       if (sizeof(char*)<sizeof(intptr_t) && ret_loc) {
2370         ((int*)W_OFFSET(dst,delta))[0] = 0;
2371       }
2372 #     endif /* FFI_CALLBACK_NEED_INT_CLEAR */
2373 
2374       if (SCHEME_FALSEP(val)||SCHEME_PATH_STRINGP(val)) {
2375         char* tmp;
2376         tmp = MZ_TYPE_CAST(char*, SCHEME_FALSEP(val)?NULL:SCHEME_PATH_VAL(TO_PATH(val)));
2377         if (basetype_p == NULL || tmp == NULL || 0) {
2378           (((char**)W_OFFSET(dst,delta))[0]) = tmp;
2379           return NULL;
2380         } else {
2381           *basetype_p = FOREIGN_path;
2382           return tmp;
2383         }
2384       } else {
2385         return wrong_value(who, "_path", val);;
2386         return NULL; /* hush the compiler */
2387       }
2388     case FOREIGN_symbol:
2389 #     ifdef SCHEME_BIG_ENDIAN
2390       if (sizeof(char*)<sizeof(intptr_t) && ret_loc) {
2391         ((int*)W_OFFSET(dst,delta))[0] = 0;
2392         delta += (sizeof(intptr_t)-sizeof(char*));
2393       }
2394 #     endif /* SCHEME_BIG_ENDIAN */
2395 #     ifdef FFI_CALLBACK_NEED_INT_CLEAR
2396       if (sizeof(char*)<sizeof(intptr_t) && ret_loc) {
2397         ((int*)W_OFFSET(dst,delta))[0] = 0;
2398       }
2399 #     endif /* FFI_CALLBACK_NEED_INT_CLEAR */
2400 
2401       if (SCHEME_SYMBOLP(val)) {
2402         char* tmp;
2403         tmp = MZ_TYPE_CAST(char*, SCHEME_SYM_VAL(val));
2404         if (basetype_p == NULL || tmp == NULL || !is_gcable_pointer(val)) {
2405           (((char**)W_OFFSET(dst,delta))[0]) = tmp;
2406           return NULL;
2407         } else {
2408           *basetype_p = FOREIGN_symbol;
2409           return tmp;
2410         }
2411       } else {
2412         return wrong_value(who, "_symbol", val);;
2413         return NULL; /* hush the compiler */
2414       }
2415     case FOREIGN_pointer:
2416 #     ifdef SCHEME_BIG_ENDIAN
2417       if (sizeof(void*)<sizeof(intptr_t) && ret_loc) {
2418         ((int*)W_OFFSET(dst,delta))[0] = 0;
2419         delta += (sizeof(intptr_t)-sizeof(void*));
2420       }
2421 #     endif /* SCHEME_BIG_ENDIAN */
2422 #     ifdef FFI_CALLBACK_NEED_INT_CLEAR
2423       if (sizeof(void*)<sizeof(intptr_t) && ret_loc) {
2424         ((int*)W_OFFSET(dst,delta))[0] = 0;
2425       }
2426 #     endif /* FFI_CALLBACK_NEED_INT_CLEAR */
2427       val = unwrap_cpointer_property(val);
2428       if (SCHEME_FFIANYPTRP(val)) {
2429         void* tmp; intptr_t toff;
2430         tmp = MZ_TYPE_CAST(void*, SCHEME_FFIANYPTR_VAL(val));
2431         toff = SCHEME_FFIANYPTR_OFFSET(val);
2432         if (basetype_p == NULL || (tmp == NULL && toff == 0) || !is_gcable_pointer(val)) {
2433           if (_offset) *_offset = 0;
2434           (((void**)W_OFFSET(dst,delta))[0]) = (void*)W_OFFSET(tmp, toff);;
2435           return NULL;
2436         } else {
2437           *basetype_p = FOREIGN_pointer;
2438           toff = SCHEME_FFIANYPTR_OFFSET(val);
2439           if (_offset) *_offset = toff;
2440           return _offset ? tmp : (void*)W_OFFSET(tmp, toff);
2441         }
2442       } else {
2443         return wrong_value(who, "_pointer", val);;
2444         return NULL; /* hush the compiler */
2445       }
2446     case FOREIGN_gcpointer:
2447 #     ifdef SCHEME_BIG_ENDIAN
2448       if (sizeof(void*)<sizeof(intptr_t) && ret_loc) {
2449         ((int*)W_OFFSET(dst,delta))[0] = 0;
2450         delta += (sizeof(intptr_t)-sizeof(void*));
2451       }
2452 #     endif /* SCHEME_BIG_ENDIAN */
2453 #     ifdef FFI_CALLBACK_NEED_INT_CLEAR
2454       if (sizeof(void*)<sizeof(intptr_t) && ret_loc) {
2455         ((int*)W_OFFSET(dst,delta))[0] = 0;
2456       }
2457 #     endif /* FFI_CALLBACK_NEED_INT_CLEAR */
2458       val = unwrap_cpointer_property(val);
2459       if (SCHEME_FFIANYPTRP(val)) {
2460         void* tmp; intptr_t toff;
2461         tmp = MZ_TYPE_CAST(void*, SCHEME_FFIANYPTR_VAL(val));
2462         toff = SCHEME_FFIANYPTR_OFFSET(val);
2463         if (basetype_p == NULL || (tmp == NULL && toff == 0) || 0) {
2464           if (_offset) *_offset = 0;
2465           (((void**)W_OFFSET(dst,delta))[0]) = (void*)W_OFFSET(tmp, toff);;
2466           return NULL;
2467         } else {
2468           *basetype_p = FOREIGN_gcpointer;
2469           toff = SCHEME_FFIANYPTR_OFFSET(val);
2470           if (_offset) *_offset = toff;
2471           return _offset ? tmp : (void*)W_OFFSET(tmp, toff);
2472         }
2473       } else {
2474         return wrong_value(who, "_gcpointer", val);;
2475         return NULL; /* hush the compiler */
2476       }
2477     case FOREIGN_scheme:
2478 #     ifdef SCHEME_BIG_ENDIAN
2479       if (sizeof(Scheme_Object*)<sizeof(intptr_t) && ret_loc) {
2480         ((int*)W_OFFSET(dst,delta))[0] = 0;
2481         delta += (sizeof(intptr_t)-sizeof(Scheme_Object*));
2482       }
2483 #     endif /* SCHEME_BIG_ENDIAN */
2484 #     ifdef FFI_CALLBACK_NEED_INT_CLEAR
2485       if (sizeof(Scheme_Object*)<sizeof(intptr_t) && ret_loc) {
2486         ((int*)W_OFFSET(dst,delta))[0] = 0;
2487       }
2488 #     endif /* FFI_CALLBACK_NEED_INT_CLEAR */
2489 
2490       if (1) {
2491         Scheme_Object* tmp;
2492         tmp = MZ_TYPE_CAST(Scheme_Object*, val);
2493         if (basetype_p == NULL || tmp == NULL || 0) {
2494           (((Scheme_Object**)W_OFFSET(dst,delta))[0]) = tmp;
2495           return NULL;
2496         } else {
2497           *basetype_p = FOREIGN_scheme;
2498           return tmp;
2499         }
2500       } else {
2501         return wrong_value(who, "_scheme", val);;
2502         return NULL; /* hush the compiler */
2503       }
2504     case FOREIGN_fpointer:
2505 #     ifdef SCHEME_BIG_ENDIAN
2506       if (sizeof(void*)<sizeof(intptr_t) && ret_loc) {
2507         ((int*)W_OFFSET(dst,delta))[0] = 0;
2508         delta += (sizeof(intptr_t)-sizeof(void*));
2509       }
2510 #     endif /* SCHEME_BIG_ENDIAN */
2511 #     ifdef FFI_CALLBACK_NEED_INT_CLEAR
2512       if (sizeof(void*)<sizeof(intptr_t) && ret_loc) {
2513         ((int*)W_OFFSET(dst,delta))[0] = 0;
2514       }
2515 #     endif /* FFI_CALLBACK_NEED_INT_CLEAR */
2516       if (!(ret_loc)) return wrong_value(who, "_fpointer", val);;
2517       break;
2518     case FOREIGN_struct:
2519     case FOREIGN_array:
2520     case FOREIGN_union:
2521       val = unwrap_cpointer_property(val);
2522       if (!SCHEME_FFIANYPTRP(val)) {
2523         switch (CTYPE_PRIMLABEL(type)) {
2524         case FOREIGN_struct:
2525           return wrong_value(who, "(_struct ....)", val);
2526           break;
2527         case FOREIGN_array:
2528           return wrong_value(who, "(_array ....)", val);
2529           break;
2530         default:
2531         case FOREIGN_union:
2532           return wrong_value(who, "(_union ....)", val);
2533           break;
2534         }
2535       }
2536       {
2537         void* p = SCHEME_FFIANYPTR_VAL(val);
2538         intptr_t poff = SCHEME_FFIANYPTR_OFFSET(val);
2539         if (basetype_p == NULL) {
2540           if (p == NULL && poff == 0)
2541             scheme_signal_error("FFI pointer value was NULL");
2542           memcpy(W_OFFSET(dst, delta), W_OFFSET(p, poff),
2543                  CTYPE_PRIMTYPE(type)->size);
2544           return NULL;
2545         } else {
2546           *basetype_p = CTYPE_PRIMLABEL(type);
2547           if (_offset && is_gcable_pointer(val)) {
2548             *_offset = poff;
2549             return p;
2550           } else {
2551             return W_OFFSET(p, poff);
2552           }
2553         }
2554       }
2555     default: scheme_signal_error("corrupt foreign type: %V", type);
2556   }
2557   return NULL; /* hush the compiler */
2558 }
2559 #undef SET_CTYPE
2560 
2561 /*****************************************************************************/
2562 /* C type information */
2563 
2564 /* (ctype-sizeof type) -> int, returns 0 for void, error if not a C type */
2565 #define MYNAME "ctype-sizeof"
foreign_ctype_sizeof(int argc,Scheme_Object * argv[])2566 static Scheme_Object *foreign_ctype_sizeof(int argc, Scheme_Object *argv[])
2567 {
2568   intptr_t size;
2569   size = ctype_sizeof(argv[0]);
2570   if (size >= 0) return scheme_make_integer(size);
2571   else scheme_wrong_contract(MYNAME, "ctype?", 0, argc, argv);
2572   return NULL; /* hush the compiler */
2573 }
2574 #undef MYNAME
2575 
2576 /* (ctype-alignof type) -> int, returns 0 for void, error if not a C type */
2577 #define MYNAME "ctype-alignof"
foreign_ctype_alignof(int argc,Scheme_Object * argv[])2578 static Scheme_Object *foreign_ctype_alignof(int argc, Scheme_Object *argv[])
2579 {
2580   Scheme_Object *type;
2581   type = get_ctype_base(argv[0]);
2582   if (type == NULL) scheme_wrong_contract(MYNAME, "ctype?", 0, argc, argv);
2583   else return scheme_make_integer(CTYPE_PRIMTYPE(type)->alignment);
2584   return NULL; /* hush the compiler */
2585 }
2586 #undef MYNAME
2587 
2588 /* (compiler-sizeof symbols) -> int, where symbols name some C type.
2589  * The symbols are in 'int 'char 'void 'short 'long '*, order does not matter,
2590  * when a single symbol is used, a list is not needed.
2591  * (This is about actual C types, not C type objects.) */
2592 #define MYNAME "compiler-sizeof"
foreign_compiler_sizeof(int argc,Scheme_Object * argv[])2593 static Scheme_Object *foreign_compiler_sizeof(int argc, Scheme_Object *argv[])
2594 {
2595   int res=0;
2596   int basetype = 0; /* 1=int, 2=char, 3=void, 4=float, 5=double, 6=wchar_t */
2597   int intsize = 0;  /* "short" => decrement, "long" => increment */
2598   int stars = 0;    /* number of "*"s */
2599   int must_list = 0;
2600   Scheme_Object *l = argv[0], *p;
2601   while (!SAME_OBJ(l, scheme_null)) {
2602     if (SCHEME_PAIRP(l)) { p = SCHEME_CAR(l); l = SCHEME_CDR(l); must_list = 1;}
2603     else if (must_list) { p = scheme_false; l = scheme_null; }
2604     else { p = l; l = scheme_null; }
2605     if (!SCHEME_SYMBOLP(p)) {
2606       scheme_wrong_contract(MYNAME, "(or/c symbol? (listof symbol?))", 0, argc, argv);
2607     } else if (!strcmp(SCHEME_SYM_VAL(p),"int")) {
2608       if (basetype==0) basetype=1;
2609       else scheme_signal_error(MYNAME": extraneous type: %V", p);
2610     } else if (!strcmp(SCHEME_SYM_VAL(p),"char")) {
2611       if (basetype==0) basetype=2;
2612       else scheme_signal_error(MYNAME": extraneous type: %V", p);
2613     } else if (!strcmp(SCHEME_SYM_VAL(p),"wchar")) {
2614       if (basetype==0) basetype=6;
2615       else scheme_signal_error(MYNAME": extraneous type: %V", p);
2616     } else if (!strcmp(SCHEME_SYM_VAL(p),"void")) {
2617       if (basetype==0) basetype=3;
2618       else scheme_signal_error(MYNAME": extraneous type: %V", p);
2619     } else if (!strcmp(SCHEME_SYM_VAL(p),"float")) {
2620       if (basetype==0) basetype=4;
2621       else scheme_signal_error(MYNAME": extraneous type: %V", p);
2622     } else if (!strcmp(SCHEME_SYM_VAL(p),"double")) {
2623       if (basetype==0 || basetype==4) basetype=5;
2624       else scheme_signal_error(MYNAME": extraneous type: %V", p);
2625     } else if (!strcmp(SCHEME_SYM_VAL(p),"short")) {
2626       if (intsize>0)
2627         scheme_signal_error(MYNAME": cannot use both 'short and 'long");
2628       else intsize--;
2629     } else if (!strcmp(SCHEME_SYM_VAL(p),"long")) {
2630       if (intsize<0)
2631         scheme_signal_error(MYNAME": cannot use both 'short and 'long");
2632       else intsize++;
2633     } else if (!strcmp(SCHEME_SYM_VAL(p),"*")) {
2634       stars++;
2635     } else {
2636       scheme_wrong_contract(MYNAME, "(or/c ctype-symbol? (listof ctype-symbol?))", 0, argc, argv);
2637     }
2638   }
2639   if (stars > 1)
2640     scheme_signal_error(MYNAME": cannot handle more than one '*");
2641   if (intsize < -1)
2642     scheme_signal_error(MYNAME": cannot handle more than one 'short");
2643   if (intsize > 2)
2644     scheme_signal_error(MYNAME": cannot handle more than two 'long");
2645   if (basetype == 0) basetype = 1; /* int is the default type */
2646   /* don't assume anything, so it can be used to verify compiler assumptions */
2647   /* (only forbid stuff that the compiler doesn't allow) */
2648 # define RETSIZE(t) res=((stars==0)?sizeof(t):sizeof(t *))
2649   switch (basetype) {
2650   case 1: /* int */
2651     switch (intsize) {
2652     case 0:  RETSIZE(int); break;
2653     case 1:  RETSIZE(long int); break;
2654 #   ifdef INT64_AS_LONG_LONG
2655     case 2:  RETSIZE(_int64); break; /* MSVC doesn't allow long long */
2656 #   else /* INT64_AS_LONG_LONG undefined */
2657     case 2:  RETSIZE(long long int); break;
2658 #   endif /* INT64_AS_LONG_LONG */
2659     case -1: RETSIZE(short int); break;
2660     }
2661     break;
2662   case 2: /* char */
2663     if (intsize==0) RETSIZE(char);
2664     else scheme_signal_error(MYNAME": cannot qualify 'char");
2665     break;
2666   case 3: /* void */
2667     if (intsize==0 && stars>0) RETSIZE(int); /* avoid sizeof(void) */
2668     else if (stars==0)
2669       scheme_signal_error(MYNAME": cannot use 'void without a '*");
2670     else scheme_signal_error(MYNAME": cannot qualify 'void");
2671     break;
2672   case 4: /* float */
2673     if (intsize==0) RETSIZE(float);
2674     else scheme_signal_error(MYNAME": bad qualifiers for 'float");
2675     break;
2676   case 5: /* double */
2677     if (intsize==0) RETSIZE(double);
2678     else if (intsize==1) RETSIZE(mz_long_double);
2679     else scheme_signal_error(MYNAME": bad qualifiers for 'double");
2680     break;
2681   case 6: /* wchar_t */
2682     if (intsize==0) RETSIZE(wchar_t);
2683     else scheme_signal_error(MYNAME": cannot qualify 'wchar");
2684     break;
2685   default:
2686     scheme_signal_error(MYNAME": internal error (unexpected type %d)",
2687                         basetype);
2688   }
2689 # undef RETSIZE
2690   return scheme_make_integer(res);
2691 }
2692 #undef MYNAME
2693 
2694 /*****************************************************************************/
2695 /* Pointer type user functions */
2696 
mode_to_allocator(const char * who,Scheme_Object * mode)2697 static Scheme_Malloc_Proc mode_to_allocator(const char *who, Scheme_Object *mode)
2698 {
2699   Scheme_Malloc_Proc mf;
2700 
2701   if (SAME_OBJ(mode, nonatomic_sym))          mf = scheme_malloc;
2702   else if (SAME_OBJ(mode, atomic_sym))        mf = scheme_malloc_atomic;
2703   else if (SAME_OBJ(mode, stubborn_sym))      mf = scheme_malloc_stubborn;
2704   else if (SAME_OBJ(mode, eternal_sym))       mf = scheme_malloc_eternal;
2705   else if (SAME_OBJ(mode, uncollectable_sym)) mf = scheme_malloc_uncollectable;
2706   else if (SAME_OBJ(mode, interior_sym))      mf = scheme_malloc_allow_interior;
2707   else if (SAME_OBJ(mode, atomic_interior_sym)) mf = scheme_malloc_atomic_allow_interior;
2708   else if (SAME_OBJ(mode, raw_sym))           mf = malloc;
2709   else if (SAME_OBJ(mode, tagged_sym))        mf = scheme_malloc_tagged;
2710   else {
2711     scheme_signal_error("%s: bad allocation mode: %V", who, mode);
2712     return NULL; /* hush the compiler */
2713   }
2714 
2715   return mf;
2716 }
2717 
ctype_allocator(Scheme_Object * type)2718 static Scheme_Malloc_Proc ctype_allocator(Scheme_Object *type)
2719 {
2720   Scheme_Object *mode;
2721 
2722   mode = CTYPE_BASETYPE(type);
2723   if (!SCHEME_PAIRP(mode))
2724     mode = atomic_sym;
2725   else {
2726     mode = SCHEME_CAR(mode);
2727     if (!SCHEME_SYMBOLP(mode))
2728       mode = atomic_sym;
2729   }
2730 
2731   return mode_to_allocator("_struct", mode);
2732 }
2733 
2734 /* (malloc num type cpointer mode) -> pointer */
2735 /* The arguments for this function are:
2736  * - num: bytes to allocate, or the number of instances of type when given,
2737  * - type: malloc the size of this type (or num instances of it),
2738  * - cpointer: a source pointer to copy contents from,
2739  * - mode: a symbol for different allocation functions to use - one of
2740  *   'nonatomic, 'atomic, 'stubborn, 'uncollectable, 'eternal, 'tagged,
2741  *   or 'raw (the last one is for using the real malloc)
2742  * - if an additional 'fail-ok flag is given, then scheme_malloc_fail_ok is
2743  *   used with the chosen malloc function
2744  * The arguments can be specified in any order at all since they are all
2745  * different types, the only requirement is for a size, either a number of
2746  * bytes or a type.  If no mode is specified, then scheme_malloc will be used
2747  * when the type is any pointer, otherwise scheme_malloc_atomic is used. */
2748 #define MYNAME "malloc"
foreign_malloc(int argc,Scheme_Object * argv[])2749 static Scheme_Object *foreign_malloc(int argc, Scheme_Object *argv[])
2750 {
2751   int i, failok=0;
2752   intptr_t size=0, num=-1;
2753   void *from = NULL, *res = NULL;
2754   intptr_t foff = 0;
2755   Scheme_Object *mode = NULL, *a, *base = NULL;
2756   Scheme_Malloc_Proc mf;
2757   for (i=0; i<argc; i++) {
2758     a = unwrap_cpointer_property(argv[i]);
2759     if (SCHEME_INTP(a)) {
2760       if (num != -1)
2761         scheme_signal_error(MYNAME": specifying a second integer size: %V", a);
2762       num = SCHEME_INT_VAL(a);
2763       if (num < 0)
2764         scheme_wrong_contract(MYNAME, "(and/c exact-nonnegative-integer? fixnum?)", 0, argc, argv);
2765     } else if (SCHEME_CTYPEP(a)) {
2766       if (size != 0)
2767         scheme_signal_error(MYNAME": specifying a second type: %V", a);
2768       if (NULL == (base = get_ctype_base(a)))
2769         scheme_wrong_contract(MYNAME, "ctype?", i, argc, argv);
2770       size = ctype_sizeof(a);
2771       if (size <= 0)
2772         wrong_void(MYNAME, NULL, 0, i, argc, argv);
2773     } else if (SAME_OBJ(a, fail_ok_sym)) {
2774       failok = 1;
2775     } else if (SCHEME_SYMBOLP(a)) {
2776       if (mode != NULL)
2777         scheme_signal_error(MYNAME": specifying a second mode symbol: %V", a);
2778       mode = a;
2779     } else if (SCHEME_FFIANYPTRP(a) && !SCHEME_FALSEP(a)) {
2780       if (from != NULL)
2781         scheme_signal_error(MYNAME": specifying a second source pointer: %V",
2782                             a);
2783       from = SCHEME_FFIANYPTR_VAL(a);
2784       foff = SCHEME_FFIANYPTR_OFFSET(a);
2785     } else {
2786       scheme_wrong_contract(MYNAME,
2787                             "(or/c (and/c exact-nonnegative-integer? fixnum?)\n"
2788                             "      ctype?\n"
2789                             "      (or/c 'nonatomic 'stubborn 'uncollectable\n"
2790                             "             'eternal 'interior 'atomic-interior\n"
2791                             "             'tagged 'raw)\n"
2792                             "      'fail-on\n"
2793                             "      (and/c cpointer? (not/c #f)))",
2794                             i, argc, argv);
2795     }
2796   }
2797   if (!num) return scheme_false;
2798   if ((num == -1) && (size == 0)) scheme_signal_error(MYNAME": no size given");
2799   size = mult_check_overflow(MYNAME, ((size==0) ? 1 : size), ((num==-1) ? 1 : num));
2800   if (mode == NULL)
2801     mf = (base != NULL && CTYPE_PRIMTYPE(base) == &ffi_type_gcpointer)
2802       ? scheme_malloc : scheme_malloc_atomic;
2803   else
2804     mf = mode_to_allocator(MYNAME, mode);
2805   res = scheme_malloc_fail_ok(mf,size);
2806   if (failok && (res == NULL)) scheme_signal_error("malloc: out of memory");
2807 
2808   /* We might want to use foff as the object base address if from is NULL,
2809    * therefore set a src point to use in memcpy to clarify this */
2810   {
2811     void *src = NULL;
2812     if (from != NULL)
2813       src = W_OFFSET(from, foff);
2814     else if (foff != 0)
2815       src = (void *)foff;
2816     if (src != NULL && res != NULL)
2817       memcpy(res, src, size);
2818   }
2819 
2820   if (SAME_OBJ(mode, raw_sym))
2821     return scheme_make_foreign_external_cpointer(res);
2822   else
2823     return scheme_make_foreign_cpointer(res);
2824 }
2825 #undef MYNAME
2826 
2827 #define NON_NULL_CPOINTER "(and/c cpointer? (not/c (lambda (p) (pointer-equal? p #f))))"
2828 
2829 /* (end-stubborn-change ptr) */
2830 #define MYNAME "end-stubborn-change"
foreign_end_stubborn_change(int argc,Scheme_Object * argv[])2831 static Scheme_Object *foreign_end_stubborn_change(int argc, Scheme_Object *argv[])
2832 {
2833   void *ptr;
2834   intptr_t poff;
2835   Scheme_Object *cp;
2836   cp = unwrap_cpointer_property(argv[0]);
2837   if (!SCHEME_FFIANYPTRP(cp))
2838     scheme_wrong_contract(MYNAME, "cpointer?", 0, argc, argv);
2839   ptr = SCHEME_FFIANYPTR_VAL(cp);
2840   poff = SCHEME_FFIANYPTR_OFFSET(cp);
2841   if ((ptr == NULL) && (poff == 0))
2842     scheme_wrong_contract(MYNAME, NON_NULL_CPOINTER, 0, argc, argv);
2843   scheme_end_stubborn_change(W_OFFSET(ptr, poff));
2844   return scheme_void;
2845 }
2846 #undef MYNAME
2847 
2848 /* (free ptr) */
2849 /* This is useful for raw-malloced objects, including objects from C libraries
2850  * that the library is mallocing itself. */
2851 #define MYNAME "free"
foreign_free(int argc,Scheme_Object * argv[])2852 static Scheme_Object *foreign_free(int argc, Scheme_Object *argv[])
2853 {
2854   void *ptr;
2855   intptr_t poff;
2856   Scheme_Object *cp;
2857   cp = unwrap_cpointer_property(argv[0]);
2858   if (!SCHEME_FFIANYPTRP(cp))
2859     scheme_wrong_contract(MYNAME, "cpointer?", 0, argc, argv);
2860   ptr = SCHEME_FFIANYPTR_VAL(cp);
2861   poff = SCHEME_FFIANYPTR_OFFSET(cp);
2862   if ((ptr == NULL) && (poff == 0))
2863     scheme_wrong_contract(MYNAME, NON_NULL_CPOINTER, 0, argc, argv);
2864   free(W_OFFSET(ptr, poff));
2865   return scheme_void;
2866 }
2867 #undef MYNAME
2868 
2869 /* (malloc-immobile-cell v) */
2870 #define MYNAME "malloc-immobile-cell"
foreign_malloc_immobile_cell(int argc,Scheme_Object * argv[])2871 static Scheme_Object *foreign_malloc_immobile_cell(int argc, Scheme_Object *argv[])
2872 {
2873   void *p;
2874   p = scheme_malloc_immobile_box(argv[0]);
2875   return scheme_make_foreign_external_cpointer(p); /* <- beware: macro duplicates `p' */
2876 }
2877 #undef MYNAME
2878 
2879 /* (free-immobile-cell b) */
2880 #define MYNAME "free-immobile-cell"
foreign_free_immobile_cell(int argc,Scheme_Object * argv[])2881 static Scheme_Object *foreign_free_immobile_cell(int argc, Scheme_Object *argv[])
2882 {
2883   void *ptr;
2884   intptr_t poff;
2885   Scheme_Object *cp;
2886   cp = unwrap_cpointer_property(argv[0]);
2887   if (!SCHEME_FFIANYPTRP(cp))
2888     scheme_wrong_contract(MYNAME, "cpointer?", 0, argc, argv);
2889   ptr = SCHEME_FFIANYPTR_VAL(cp);
2890   poff = SCHEME_FFIANYPTR_OFFSET(cp);
2891   if ((ptr == NULL) && (poff == 0))
2892     scheme_wrong_contract(MYNAME, NON_NULL_CPOINTER, 0, argc, argv);
2893   scheme_free_immobile_box((void **)W_OFFSET(ptr, poff));
2894   return scheme_void;
2895 }
2896 #undef MYNAME
2897 
2898 /* (ptr-add cptr offset-k [type])
2899  *   Adds an offset to a pointer, returning an offset_cpointer value
2900  * (ptr-add! cptr offset-k [type])
2901  *   Modifies an existing offset_cpointer value by adjusting its offset field,
2902  *   returns void
2903  */
do_ptr_add(const char * who,int is_bang,int argc,Scheme_Object ** argv)2904 static Scheme_Object *do_ptr_add(const char *who, int is_bang,
2905                                  int argc, Scheme_Object **argv)
2906 {
2907   intptr_t noff;
2908   Scheme_Object *cp;
2909   cp = unwrap_cpointer_property(argv[0]);
2910   if (is_bang) {
2911     if (!SCHEME_CPOINTER_W_OFFSET_P(cp))
2912       scheme_wrong_contract(who, "offset-ptr?", 0, argc, argv);
2913   } else {
2914     if (!SCHEME_FFIANYPTRP(cp))
2915       scheme_wrong_contract(who, "cpointer?", 0, argc, argv);
2916   }
2917   if (!scheme_get_int_val(argv[1], &noff))
2918     wrong_intptr(who, 1, argc, argv);
2919   if (argc > 2) {
2920     if (SCHEME_CTYPEP(argv[2])) {
2921       intptr_t size;
2922       size = ctype_sizeof(argv[2]);
2923       if (size < 0)
2924         scheme_wrong_contract(who, "ctype?", 2, argc, argv);
2925       if (size <= 0) wrong_void(who, NULL, 0, 2, argc, argv);
2926       noff = mult_check_overflow(who, noff, size);
2927     } else
2928       scheme_wrong_contract(who, "ctype?", 2, argc, argv);
2929   }
2930   if (is_bang) {
2931     intptr_t delta;
2932     delta = add_check_overflow(who, ((Scheme_Offset_Cptr*)(cp))->offset, noff);
2933     ((Scheme_Offset_Cptr*)(cp))->offset = delta;
2934     return scheme_void;
2935   } else {
2936     intptr_t delta;
2937     delta = add_check_overflow(who, SCHEME_FFIANYPTR_OFFSET(cp), noff);
2938     if (SCHEME_CPTRP(cp) && (SCHEME_CPTR_FLAGS(cp) & 0x1))
2939       return scheme_make_offset_external_cptr
2940         (SCHEME_FFIANYPTR_VAL(cp),
2941          delta,
2942          (SCHEME_CPTRP(cp)) ? SCHEME_CPTR_TYPE(cp) : NULL);
2943     else
2944       return scheme_make_offset_cptr
2945         (SCHEME_FFIANYPTR_VAL(cp),
2946          delta,
2947          (SCHEME_CPTRP(cp)) ? SCHEME_CPTR_TYPE(cp) : NULL);
2948   }
2949 }
2950 
2951 /* (ptr-add cptr offset-k [type]) */
2952 #define MYNAME "ptr-add"
foreign_ptr_add(int argc,Scheme_Object * argv[])2953 static Scheme_Object *foreign_ptr_add(int argc, Scheme_Object *argv[])
2954 {
2955   return do_ptr_add(MYNAME, 0, argc, argv);
2956 }
2957 #undef MYNAME
2958 /* (ptr-add! cptr offset-k [type]) */
2959 #define MYNAME "ptr-add!"
foreign_ptr_add_bang(int argc,Scheme_Object * argv[])2960 static Scheme_Object *foreign_ptr_add_bang(int argc, Scheme_Object *argv[])
2961 {
2962   return do_ptr_add(MYNAME, 1, argc, argv);
2963 }
2964 #undef MYNAME
2965 
2966 /* (offset-ptr? x) */
2967 /* Returns #t if the argument is a cpointer with an offset */
2968 #define MYNAME "offset-ptr?"
foreign_offset_ptr_p(int argc,Scheme_Object * argv[])2969 static Scheme_Object *foreign_offset_ptr_p(int argc, Scheme_Object *argv[])
2970 {
2971   Scheme_Object *cp;
2972   cp = unwrap_cpointer_property(argv[0]);
2973   return (SCHEME_CPOINTER_W_OFFSET_P(cp)) ? scheme_true : scheme_false;
2974 }
2975 #undef MYNAME
2976 
2977 /* (ptr-offset ptr) */
2978 /* Returns the offset of a cpointer (0 if it's not an offset pointer) */
2979 #define MYNAME "ptr-offset"
foreign_ptr_offset(int argc,Scheme_Object * argv[])2980 static Scheme_Object *foreign_ptr_offset(int argc, Scheme_Object *argv[])
2981 {
2982   Scheme_Object *cp;
2983   cp = unwrap_cpointer_property(argv[0]);
2984   if (!SCHEME_FFIANYPTRP(cp))
2985     scheme_wrong_contract(MYNAME, "cpointer?", 0, argc, argv);
2986   return scheme_make_integer_value(SCHEME_FFIANYPTR_OFFSET(cp));
2987 }
2988 #undef MYNAME
2989 
2990 /* (set-ptr-offset! ptr offset [type]) */
2991 /* Sets the offset of an offset-cpointer (possibly multiplied by the size of
2992  * the given ctype) */
2993 #define MYNAME "set-ptr-offset!"
foreign_set_ptr_offset_bang(int argc,Scheme_Object * argv[])2994 static Scheme_Object *foreign_set_ptr_offset_bang(int argc, Scheme_Object *argv[])
2995 {
2996   intptr_t noff;
2997   Scheme_Object *cp;
2998   cp = unwrap_cpointer_property(argv[0]);
2999   if (!SCHEME_CPOINTER_W_OFFSET_P(cp))
3000     scheme_wrong_contract(MYNAME, "offset-ptr?", 0, argc, argv);
3001   if (!scheme_get_int_val(argv[1], &noff))
3002     wrong_intptr(MYNAME, 1, argc, argv);
3003   if (argc > 2) {
3004     if (SCHEME_CTYPEP(argv[2])) {
3005       intptr_t size;
3006       if (NULL == get_ctype_base(argv[2]))
3007         scheme_wrong_contract(MYNAME, "ctype?", 2, argc, argv);
3008       size = ctype_sizeof(argv[2]);
3009       if (size <= 0)
3010         wrong_void(MYNAME, NULL, 0, 2, argc, argv);
3011       noff = mult_check_overflow(MYNAME, noff, size);
3012     } else
3013       scheme_wrong_contract(MYNAME, "ctype?", 2, argc, argv);
3014   }
3015   ((Scheme_Offset_Cptr*)(cp))->offset = noff;
3016   return scheme_void;
3017 }
3018 #undef MYNAME
3019 
3020 /* (mem{move,cpy} dest-ptr [dest-offset] src-ptr [src-offset] count [ctype])
3021  *   Copies count * sizeof(ctype) bytes
3022  *   from src-ptr + src-offset * sizeof(ctype)
3023  *   to dest-ptr + dest-offset * sizeof(ctype).
3024  * --or--
3025  * (memset dest-ptr [dest-offset] byte count [ctype])
3026  *   Sets count * sizeof(ctype) bytes to byte
3027  *   at dest-ptr + dest-offset * sizeof(ctype) */
do_memop(const char * who,int mode,int argc,Scheme_Object ** argv)3028 static Scheme_Object *do_memop(const char *who, int mode,
3029                                int argc, Scheme_Object **argv)
3030 /* mode 0=>memset, 1=>memmove, 2=>memcpy */
3031 {
3032   void *src = NULL, *dest = NULL;
3033   intptr_t soff = 0, doff = 0, count, v, mult = 0;
3034   int i, j, ch = 0, argc1 = argc;
3035   Scheme_Object *cp;
3036 
3037   /* arg parsing: last optional ctype, then count, then fill byte for memset,
3038    * then the first and second pointer+offset pair. */
3039 
3040   /* get the optional last ctype multiplier */
3041   if (SCHEME_CTYPEP(argv[argc1-1])) {
3042     argc1--;
3043     mult = ctype_sizeof(argv[argc1]);
3044     if (mult < 0)
3045       scheme_wrong_contract(who, "ctype?", argc1, argc, argv);
3046     if (mult <= 0)
3047       wrong_void(who, NULL, 0, argc1, argc, argv);
3048   }
3049 
3050   /* get the count argument */
3051   argc1--;
3052   if ((!scheme_get_int_val(argv[argc1], &count)) || (count < 0))
3053     wrong_intptr(who, argc1, argc, argv);
3054   if (mult) count *= mult;
3055 
3056   /* get the fill byte for memset */
3057   if (!mode) {
3058     argc1--;
3059     ch = SCHEME_INTP(argv[argc1]) ? SCHEME_INT_VAL(argv[argc1]) : -1;
3060     if ((ch < 0) || (ch > 255))
3061       scheme_wrong_contract(who, "byte?", argc1, argc, argv);
3062   }
3063 
3064   /* get the two pointers + offsets */
3065   i = 0;
3066   for (j=0; j<2; j++) {
3067     if (!mode && j==1) break; /* memset needs only a dest argument */
3068     if (!(i<argc1))
3069       scheme_raise_exn(MZEXN_FAIL_CONTRACT,
3070                        "%s: missing a pointer argument for %s",
3071                        who, (j == 0 ? "destination" : "source"));
3072     cp = unwrap_cpointer_property(argv[i]);
3073     if (!SCHEME_FFIANYPTRP(cp))
3074       scheme_wrong_contract(who, "cpointer?", i, argc, argv);
3075     switch (j) {
3076     case 0: dest = SCHEME_FFIANYPTR_VAL(cp);
3077             doff = SCHEME_FFIANYPTR_OFFSET(cp);
3078             break;
3079     case 1: src  = SCHEME_FFIANYPTR_VAL(cp);
3080             soff = SCHEME_FFIANYPTR_OFFSET(cp);
3081             break;
3082     }
3083     i++;
3084     if ((i<argc1) && SCHEME_EXACT_INTEGERP(argv[i])) {
3085       if (!scheme_get_int_val(argv[i], &v))
3086         wrong_intptr(who, i, argc, argv);
3087       if (mult) v *= mult;
3088       switch (j) {
3089       case 0: doff += v; break;
3090       case 1: soff += v; break;
3091       }
3092       i++;
3093     }
3094   }
3095 
3096   /* verify that there are no unused leftovers */
3097   if (!(i==argc1))
3098     scheme_arg_mismatch(who, "unexpected extra argument: ", argv[i]);
3099 
3100   switch (mode) {
3101   case 0: memset (W_OFFSET(dest, doff), ch, count); break;
3102   case 1: memmove(W_OFFSET(dest, doff), W_OFFSET(src, soff), count); break;
3103   case 2: memcpy (W_OFFSET(dest, doff), W_OFFSET(src, soff), count); break;
3104   }
3105 
3106   return scheme_void;
3107 }
3108 
3109 #define MYNAME "vector->cpointer"
foreign_vector_to_cpointer(int argc,Scheme_Object * argv[])3110 static Scheme_Object *foreign_vector_to_cpointer(int argc, Scheme_Object *argv[])
3111 {
3112   if (!SCHEME_VECTORP(argv[0]))
3113     scheme_wrong_contract(MYNAME, "vector?", 0, argc, argv);
3114   return scheme_make_offset_cptr(argv[0], (intptr_t)SCHEME_VEC_ELS((Scheme_Object *)0x0), NULL);
3115 }
3116 #undef MYNAME
3117 
3118 #define MYNAME "flvector->cpointer"
foreign_flvector_to_cpointer(int argc,Scheme_Object * argv[])3119 static Scheme_Object *foreign_flvector_to_cpointer(int argc, Scheme_Object *argv[])
3120 {
3121   if (!SCHEME_FLVECTORP(argv[0]))
3122     scheme_wrong_contract(MYNAME, "flvector?", 0, argc, argv);
3123   return scheme_make_offset_cptr(argv[0], (intptr_t)SCHEME_FLVEC_ELS((Scheme_Object *)0x0), NULL);
3124 }
3125 #undef MYNAME
3126 
3127 #define MYNAME "extflvector->cpointer"
foreign_extflvector_to_cpointer(int argc,Scheme_Object * argv[])3128 static Scheme_Object *foreign_extflvector_to_cpointer(int argc, Scheme_Object *argv[])
3129 {
3130 # ifdef MZ_LONG_DOUBLE
3131   if (!SCHEME_EXTFLVECTORP(argv[0]))
3132     scheme_wrong_contract(MYNAME, "extflvector?", 0, argc, argv);
3133   return scheme_make_offset_cptr(argv[0], (intptr_t)SCHEME_EXTFLVEC_ELS((Scheme_Object *)0x0), NULL);
3134 # else /* MZ_LONG_DOUBLE undefined */
3135   scheme_raise_exn(MZEXN_FAIL_UNSUPPORTED,
3136                    MYNAME ": " NOT_SUPPORTED_STR);
3137   return NULL;
3138 # endif /* MZ_LONG_DOUBLE */
3139 }
3140 #undef MYNAME
3141 
3142 #define MYNAME "memset"
foreign_memset(int argc,Scheme_Object * argv[])3143 static Scheme_Object *foreign_memset(int argc, Scheme_Object *argv[])
3144 {
3145   return do_memop(MYNAME, 0, argc, argv);
3146 }
3147 #undef MYNAME
3148 #define MYNAME "memmove"
foreign_memmove(int argc,Scheme_Object * argv[])3149 static Scheme_Object *foreign_memmove(int argc, Scheme_Object *argv[])
3150 {
3151   return do_memop(MYNAME, 1, argc, argv);
3152 }
3153 #undef MYNAME
3154 #define MYNAME "memcpy"
foreign_memcpy(int argc,Scheme_Object * argv[])3155 static Scheme_Object *foreign_memcpy(int argc, Scheme_Object *argv[])
3156 {
3157   return do_memop(MYNAME, 2, argc, argv);
3158 }
3159 #undef MYNAME
3160 
3161 static Scheme_Object *abs_sym;
3162 
3163 /* (ptr-ref cpointer type [['abs] n]) -> the object at the given location */
3164 /* n defaults to 0 which is the only value that should be used with ffi_objs */
3165 /* if n is given, an 'abs flag can precede it to make n be a byte offset */
3166 /* rather than some multiple of sizeof(type). */
3167 /* WARNING: there are *NO* checks at all, this is raw C level code. */
3168 #define MYNAME "ptr-ref"
foreign_ptr_ref(int argc,Scheme_Object * argv[])3169 static Scheme_Object *foreign_ptr_ref(int argc, Scheme_Object *argv[])
3170 {
3171   intptr_t size=0; void *ptr; Scheme_Object *base;
3172   intptr_t delta; int gcsrc=1;
3173   Scheme_Object *cp, *already_ptr = NULL;
3174   cp = unwrap_cpointer_property(argv[0]);
3175   if (!SCHEME_FFIANYPTRP(cp))
3176     scheme_wrong_contract(MYNAME, "cpointer?", 0, argc, argv);
3177   ptr = SCHEME_FFIANYPTR_VAL(cp);
3178   delta = SCHEME_FFIANYPTR_OFFSET(cp);
3179   if (!is_gcable_pointer(cp))
3180     gcsrc = 0;
3181   if ((ptr == NULL) && (delta == 0))
3182     scheme_wrong_contract(MYNAME, NON_NULL_CPOINTER, 0, argc, argv);
3183   if (NULL == (base = get_ctype_base(argv[1])))
3184     scheme_wrong_contract(MYNAME, "ctype?", 1, argc, argv);
3185   size = ctype_sizeof(base);
3186 
3187   if (CTYPE_PRIMLABEL(base) == FOREIGN_fpointer) {
3188     if (SCHEME_FFIOBJP(cp)) {
3189       /* The ffiobj pointer is the function pointer. */
3190       ptr = cp;
3191       delta = (intptr_t)&(((ffi_obj_struct*)0x0)->obj);
3192       /* Helps propagate a function name from `ffi-obj' to `ffi-call': */
3193       already_ptr = cp;
3194     }
3195   }
3196 
3197   if (size < 0) {
3198     /* should not happen */
3199     scheme_wrong_contract(MYNAME, "ctype?", 1, argc, argv);
3200   } else if (size == 0) {
3201     wrong_void(MYNAME, NULL, 0, 1, argc, argv);
3202   }
3203 
3204   if (argc > 3) {
3205     if (!SAME_OBJ(argv[2],abs_sym))
3206       scheme_wrong_contract(MYNAME, "'abs", 2, argc, argv);
3207     if (!SCHEME_INTP(argv[3]))
3208       scheme_wrong_contract(MYNAME, "fixnum?", 3, argc, argv);
3209     if (SCHEME_INT_VAL(argv[3])) {
3210       delta = add_check_overflow(MYNAME, delta, SCHEME_INT_VAL(argv[3]));
3211       already_ptr = NULL;
3212     }
3213   } else if (argc > 2) {
3214     if (!SCHEME_INTP(argv[2]))
3215       scheme_wrong_contract(MYNAME, "fixnum?", 2, argc, argv);
3216     if (!size)
3217       scheme_signal_error(MYNAME": cannot multiply fpointer type by offset");
3218     if (SCHEME_INT_VAL(argv[2])) {
3219       delta = add_check_overflow(MYNAME, delta, mult_check_overflow(MYNAME, size, SCHEME_INT_VAL(argv[2])));
3220       already_ptr = NULL;
3221     }
3222   }
3223   return C2SCHEME(already_ptr, argv[1], ptr, delta, 0, gcsrc);
3224 }
3225 #undef MYNAME
3226 
scheme_foreign_ptr_ref(int argc,Scheme_Object ** argv)3227 Scheme_Object *scheme_foreign_ptr_ref(int argc, Scheme_Object **argv)
3228 {
3229   return foreign_ptr_ref(argc, argv);
3230 }
3231 
3232 /* (ptr-set! cpointer type [['abs] n] value) -> void */
3233 /* n defaults to 0 which is the only value that should be used with ffi_objs */
3234 /* if n is given, an 'abs flag can precede it to make n be a byte offset */
3235 /* rather than some multiple of sizeof(type). */
3236 /* WARNING: there are *NO* checks at all, this is raw C level code. */
3237 #define MYNAME "ptr-set!"
foreign_ptr_set_bang(int argc,Scheme_Object * argv[])3238 static Scheme_Object *foreign_ptr_set_bang(int argc, Scheme_Object *argv[])
3239 {
3240   intptr_t size=0; void *ptr;
3241   intptr_t delta;
3242   Scheme_Object *val = argv[argc-1], *base;
3243   Scheme_Object *cp;
3244   cp = unwrap_cpointer_property(argv[0]);
3245   if (!SCHEME_FFIANYPTRP(cp))
3246     scheme_wrong_contract(MYNAME, "cpointer?", 0, argc, argv);
3247   ptr = SCHEME_FFIANYPTR_VAL(cp);
3248   delta = SCHEME_FFIANYPTR_OFFSET(cp);
3249   if ((ptr == NULL) && (delta == 0))
3250     scheme_wrong_contract(MYNAME, NON_NULL_CPOINTER, 0, argc, argv);
3251   if (NULL == (base = get_ctype_base(argv[1])))
3252     scheme_wrong_contract(MYNAME, "ctype?", 1, argc, argv);
3253   size = ctype_sizeof(base);
3254 
3255   if (size < 0) {
3256     /* should not happen */
3257     scheme_wrong_contract(MYNAME, "ctype?", 1, argc, argv);
3258   } else if (size == 0) {
3259     wrong_void(MYNAME, NULL, 0, 1, argc, argv);
3260   }
3261 
3262   if (argc > 4) {
3263     if (!SAME_OBJ(argv[2],abs_sym))
3264       scheme_wrong_contract(MYNAME, "'abs", 2, argc, argv);
3265     if (!SCHEME_INTP(argv[3]))
3266       scheme_wrong_contract(MYNAME, "fixnum?", 3, argc, argv);
3267     delta = add_check_overflow(MYNAME, delta, SCHEME_INT_VAL(argv[3]));
3268   } else if (argc > 3) {
3269     if (!SCHEME_INTP(argv[2]))
3270       scheme_wrong_contract(MYNAME, "fixnum?", 2, argc, argv);
3271     if (!size)
3272       scheme_signal_error(MYNAME": cannot multiply fpointer type by offset");
3273     delta = add_check_overflow(MYNAME, delta, mult_check_overflow(MYNAME, size, SCHEME_INT_VAL(argv[2])));
3274   }
3275   SCHEME2C(MYNAME, argv[1], ptr, delta, val, NULL, NULL, 0);
3276   return scheme_void;
3277 }
3278 #undef MYNAME
3279 
scheme_foreign_ptr_set(int argc,Scheme_Object ** argv)3280 void scheme_foreign_ptr_set(int argc, Scheme_Object **argv)
3281 {
3282   (void)foreign_ptr_set_bang(argc, argv);
3283 }
3284 
3285 /* (ptr-equal? cpointer cpointer) -> boolean */
3286 #define MYNAME "ptr-equal?"
foreign_ptr_equal_p(int argc,Scheme_Object * argv[])3287 static Scheme_Object *foreign_ptr_equal_p(int argc, Scheme_Object *argv[])
3288 {
3289   Scheme_Object *cp1, *cp2;
3290   cp1 = unwrap_cpointer_property(argv[0]);
3291   cp2 = unwrap_cpointer_property(argv[1]);
3292   if (!SCHEME_FFIANYPTRP(cp1))
3293     scheme_wrong_contract(MYNAME, "cpointer?", 0, argc, argv);
3294   if (!SCHEME_FFIANYPTRP(cp2))
3295     scheme_wrong_contract(MYNAME, "cpointer?", 1, argc, argv);
3296   return (SAME_OBJ(cp1, cp2) ||
3297           (SCHEME_FFIANYPTR_OFFSETVAL(cp1)
3298            == SCHEME_FFIANYPTR_OFFSETVAL(cp2)))
3299          ? scheme_true : scheme_false;
3300 }
3301 #undef MYNAME
3302 
3303 /* (make-sized-byte-string cpointer len) */
3304 #define MYNAME "make-sized-byte-string"
foreign_make_sized_byte_string(int argc,Scheme_Object * argv[])3305 static Scheme_Object *foreign_make_sized_byte_string(int argc, Scheme_Object *argv[])
3306 {
3307   /* Warning: no copying is done so it is possible to share string contents. */
3308   /* Warning: if source ptr has a offset, resulting string object uses shifted
3309    * pointer.
3310    * (Should use real byte-strings with new version.) */
3311   intptr_t len;
3312   Scheme_Object *cp;
3313   cp = unwrap_cpointer_property(argv[0]);
3314   if (!SCHEME_FFIANYPTRP(cp))
3315     scheme_wrong_contract(MYNAME, "cpointer?", 0, argc, argv);
3316   if (!scheme_get_int_val(argv[1],&len))
3317     wrong_intptr(MYNAME, 1, argc, argv);
3318   return scheme_make_sized_byte_string(SCHEME_FFIANYPTR_OFFSETVAL(cp),
3319                                        len, 0);
3320 }
3321 #undef MYNAME
3322 
3323 /*****************************************************************************/
3324 /* FFI named locks */
3325 
3326 THREAD_LOCAL_DECL(static Scheme_Hash_Table *ffi_lock_ht);
3327 
3328 #if defined(MZ_PRECISE_GC) && defined(MZ_USE_PLACES)
make_vector_in_master(int count,Scheme_Object * val)3329 static Scheme_Object *make_vector_in_master(int count, Scheme_Object *val) {
3330   Scheme_Object *vec;
3331   void *original_gc;
3332   original_gc = GC_switch_to_master_gc();
3333   vec = scheme_make_vector(count, val);
3334   GC_switch_back_from_master(original_gc);
3335   return vec;
3336 }
3337 
malloc_immobile_box_in_master(Scheme_Object * v)3338 static void **malloc_immobile_box_in_master(Scheme_Object *v)
3339 {
3340   void **imm;
3341   void *original_gc;
3342   original_gc = GC_switch_to_master_gc();
3343   imm = scheme_malloc_immobile_box(v);
3344   GC_switch_back_from_master(original_gc);
3345   return imm;
3346 }
3347 #endif
3348 
name_to_ffi_lock(Scheme_Object * bstr)3349 static void *name_to_ffi_lock(Scheme_Object *bstr)
3350 {
3351   Scheme_Object *lock;
3352 
3353   if (!ffi_lock_ht) {
3354     REGISTER_SO(ffi_lock_ht);
3355     ffi_lock_ht = scheme_make_hash_table_equal();
3356   }
3357 
3358   lock = scheme_hash_get(ffi_lock_ht, bstr);
3359   if (!lock) {
3360 #   ifdef MZ_USE_PLACES
3361     /* implement the lock with a compare-and-swap with fallback (on
3362        contention) to a place channel; this strategy has minimal
3363        overhead when there's no contention, which is good for avoiding
3364        a penalty in the common case of a single place (but it's probably
3365        not the best strategy for a contended lock) */
3366     void *lock_box, *old_lock_box;
3367 
3368     lock_box = scheme_register_process_global(SCHEME_BYTE_STR_VAL(bstr), NULL);
3369     if (!lock_box) {
3370       lock = scheme_place_make_async_channel();
3371       lock = make_vector_in_master(2, lock);
3372       SCHEME_VEC_ELS(lock)[1] = scheme_make_integer(-1);
3373       lock_box = malloc_immobile_box_in_master(lock);
3374       old_lock_box = scheme_register_process_global(SCHEME_BYTE_STR_VAL(bstr), lock_box);
3375       if (old_lock_box) {
3376         scheme_free_immobile_box(lock_box);
3377         lock_box = old_lock_box;
3378       }
3379     }
3380     lock = *(Scheme_Object **)lock_box;
3381 #   else /* MZ_USE_PLACES undefined */
3382     lock = scheme_make_sema(1);
3383 #   endif /* MZ_USE_PLACES */
3384     scheme_hash_set(ffi_lock_ht, bstr, lock);
3385   }
3386 
3387   return lock;
3388 }
3389 
wait_ffi_lock(Scheme_Object * lock)3390 static void wait_ffi_lock(Scheme_Object *lock)
3391 {
3392 # ifdef MZ_USE_PLACES
3393   while (1) {
3394     if (mzrt_cas((uintptr_t*)&(SCHEME_VEC_ELS(lock)[1]),
3395                  (uintptr_t)scheme_make_integer(-1),
3396                  (uintptr_t)scheme_make_integer(scheme_current_place_id))) {
3397       /* obtained lock the fast way */
3398       break;
3399     } else if (!scheme_place_can_receive()) {
3400       /* We can get here while trying to terminate a place and run
3401          custodian callbacks or other shutdown actions, and since
3402          the place is shutting down, we can't commuincate with other
3403          places; since we can't pause nicely, just spin */
3404     } else {
3405       Scheme_Object *owner, *new_val;
3406       owner = SCHEME_VEC_ELS(lock)[1];
3407       if (SCHEME_INT_VAL(owner) != -1) {
3408         if (SCHEME_INT_VAL(owner) < -1) {
3409           /* other processes waiting, and now there's one more: */
3410           new_val = scheme_make_integer(SCHEME_INT_VAL(owner)-1);
3411         } else {
3412           /* notify owner that another process is now waiting: */
3413           new_val = scheme_make_integer(-2);
3414         }
3415         if (mzrt_cas((uintptr_t*)&(SCHEME_VEC_ELS(lock)[1]),
3416                      (uintptr_t)owner,
3417                      (uintptr_t)new_val)) {
3418           /* wait for lock the slow way - without blocking other Racket threads */
3419           (void)scheme_place_async_channel_receive(SCHEME_VEC_ELS(lock)[0]);
3420 
3421           /* not waiting anymore: */
3422           while (1) {
3423             owner = SCHEME_VEC_ELS(lock)[1];
3424             if (SCHEME_INT_VAL(owner) == -2) {
3425               /* no other processes waiting */
3426               new_val = scheme_make_integer(scheme_current_place_id);
3427             } else {
3428               /* one less process waiting */
3429               new_val = scheme_make_integer(SCHEME_INT_VAL(owner)+1);
3430             }
3431             if (mzrt_cas((uintptr_t*)&(SCHEME_VEC_ELS(lock)[1]),
3432                          (uintptr_t)owner,
3433                          (uintptr_t)new_val)) {
3434               break;
3435             }
3436           }
3437           break;
3438         }
3439       }
3440     }
3441   }
3442 # else /* MZ_USE_PLACES undefined */
3443   scheme_wait_sema(lock, 0);
3444 # endif /* MZ_USE_PLACES */
3445 }
3446 
release_ffi_lock(void * lock)3447 static void release_ffi_lock(void *lock)
3448 {
3449 # ifdef MZ_USE_PLACES
3450   if (mzrt_cas((uintptr_t *)&(SCHEME_VEC_ELS(lock)[1]),
3451                (uintptr_t)scheme_make_integer(scheme_current_place_id),
3452                (uintptr_t)scheme_make_integer(-1))) {
3453     /* released lock with no other process waiting */
3454   } else {
3455     /* assert: SCHEME_VEC_ELS(lock)[1] holds a negative
3456        number corresponding to the number of waiting processes */
3457     scheme_place_async_channel_send(SCHEME_VEC_ELS(lock)[0], scheme_false);
3458   }
3459 # else /* MZ_USE_PLACES undefined */
3460   scheme_post_sema(lock);
3461 # endif /* MZ_USE_PLACES */
3462 }
3463 
3464 /*****************************************************************************/
3465 
extract_varargs_after(const char * who,int argc,Scheme_Object ** argv,int argpos,int nargs)3466 static int extract_varargs_after(const char *who, int argc, Scheme_Object **argv, int argpos, int nargs)
3467 {
3468   int varargs_after;
3469 
3470   if (SCHEME_FALSEP(argv[argpos]))
3471     varargs_after = -1;
3472   else if (SCHEME_INTP(argv[argpos])
3473            && (SCHEME_INT_VAL(argv[argpos]) > 0)) {
3474     varargs_after = SCHEME_INT_VAL(argv[argpos]);
3475   } else if (SCHEME_BIGNUMP(argv[argpos])
3476              && SCHEME_BIGPOS((argv[argpos]))) {
3477     varargs_after = nargs + 1;
3478   } else {
3479     varargs_after = -1;
3480     scheme_wrong_contract(who, "(or/c exact-positive-integer? #f)", argpos, argc, argv);
3481   }
3482   if (varargs_after > nargs)
3483     scheme_contract_error(who, "varargs-after value is too large",
3484                           "given value", 1, argv[argpos],
3485                           "argument count", 1, scheme_make_integer(nargs),
3486                           NULL);
3487 
3488   return varargs_after;
3489 }
3490 
3491 /*****************************************************************************/
3492 /* Calling foreign function objects */
3493 
3494 #define MAX_QUICK_ARGS 16
3495 
3496 typedef void(*VoidFun)(void);
3497 
3498 #ifdef MZ_USE_PLACES
3499 
3500 typedef struct FFI_Orig_Place_Call {
3501   int needs_queue;
3502   ffi_cif *cif;
3503   void *c_func;
3504   intptr_t cfoff;
3505   int nargs;
3506   ForeignAny *ivals;
3507   void **avalues;
3508   intptr_t *offsets;
3509   void *p;
3510   void **signal_handle;
3511   struct FFI_Orig_Place_Call *next, *prev;
3512 } FFI_Orig_Place_Call;
3513 
3514 static mzrt_mutex *orig_place_mutex;
3515 static FFI_Orig_Place_Call *orig_place_calls, *orig_place_calls_tail;
3516 static void *orig_place_signal_handle;
3517 
3518 static void check_foreign_work(int check_for_in_original);
3519 
ffi_call_in_orig_place(ffi_cif * cif,void * c_func,intptr_t cfoff,int nargs,GC_CAN_IGNORE ForeignAny * ivals,void ** avalues,intptr_t * offsets,void * p)3520 static void ffi_call_in_orig_place(ffi_cif *cif, void *c_func, intptr_t cfoff,
3521                                    int nargs, GC_CAN_IGNORE ForeignAny *ivals, void **avalues,
3522                                    intptr_t *offsets, void *p)
3523 /* This function can trigger a GC, but it won't escape --- unless
3524    the called function goes back to Racket and raises an exception,
3525    and raising an exception in a callback creates all sorts of
3526    other problems, anyway. No other Racket threads will run in the
3527    place, so it's ok for the arguments to have stack addresses. */
3528 {
3529   FFI_Orig_Place_Call *todo;
3530   void *sh;
3531   int ready;
3532 
3533   if (cached_orig_place_todo) {
3534     todo = cached_orig_place_todo;
3535     cached_orig_place_todo = NULL;
3536   } else
3537     todo = (FFI_Orig_Place_Call *)malloc(sizeof(FFI_Orig_Place_Call));
3538   sh = scheme_get_signal_handle();
3539   todo->signal_handle = sh;
3540   todo->needs_queue = 1;
3541 
3542   /* It would be simplest to just block the current place while the
3543      original place handles the call. Unfortunately, something like a
3544      master GC might be required between now and when the call is
3545      handled. So, we have to block in an atomic-like way to minimize
3546      GCs while we wait, but still wake up on an external signal. */
3547 
3548   GC_check_master_gc_request();
3549   /* If a GC is needed from here on, a signal will be posted
3550      to the current place */
3551 
3552   while (1) {
3553     todo->cif = cif;
3554     todo->c_func = c_func;
3555     todo->cfoff = cfoff;
3556     todo->nargs = nargs;
3557     todo->ivals = ivals;
3558     todo->avalues = avalues;
3559     todo->offsets = offsets;
3560     todo->p = p;
3561 
3562     mzrt_mutex_lock(orig_place_mutex);
3563     if (todo->needs_queue) {
3564       todo->next = orig_place_calls;
3565       todo->prev = NULL;
3566       if (orig_place_calls)
3567         orig_place_calls->prev = todo;
3568       else
3569         orig_place_calls_tail = todo;
3570       orig_place_calls = todo;
3571       ready = 0;
3572     } else {
3573       ready = !todo->signal_handle;
3574     }
3575     mzrt_mutex_unlock(orig_place_mutex);
3576 
3577     if (!ready) {
3578       /* Tell original-place thread that there's work: */
3579       scheme_signal_received_at(orig_place_signal_handle);
3580       /* Wait for notificiation or a master-GC request: */
3581       scheme_wait_until_signal_received();
3582     }
3583 
3584     mzrt_mutex_lock(orig_place_mutex);
3585     if (!todo->signal_handle) {
3586       /* Done */
3587       mzrt_mutex_unlock(orig_place_mutex);
3588       if (!cached_orig_place_todo)
3589         cached_orig_place_todo = todo;
3590       else
3591         free(todo);
3592       break;
3593     } else {
3594       /* Pause to allow actions such as a master GC.... */
3595       if (todo->needs_queue) {
3596         /* Remove from queue while we might GC: */
3597         if (todo->prev)
3598           todo->prev->next = todo->next;
3599         else
3600           orig_place_calls = todo->next;
3601         if (todo->next)
3602           todo->next->prev = todo->prev;
3603         else
3604           orig_place_calls_tail = todo->prev;
3605       } else {
3606         /* The call is being handled, so it's too late
3607            to remove it from the queue! */
3608       }
3609       mzrt_mutex_unlock(orig_place_mutex);
3610 
3611       /* Here's the atomic pause: */
3612       GC_check_master_gc_request();
3613       scheme_start_atomic();
3614       scheme_thread_block(0.0);
3615       scheme_end_atomic_no_swap();
3616 
3617       /* Since we called scheme_thread_block() in atomic mode,
3618          it doesn't check for foreign callbacks. We'd like
3619          to handle those anyway, since the call in the original
3620          place may lead to a callback that should run in
3621          this place. */
3622 #     ifndef MZ_USE_FFIPOLL
3623       check_foreign_work(0);
3624 #     endif /* MZ_USE_FFIPOLL */
3625     }
3626   }
3627 }
3628 #endif
3629 
finish_ffi_call(ffi_cif * cif,void * c_func,intptr_t cfoff,int nargs,GC_CAN_IGNORE ForeignAny * ivals,void ** avalues,intptr_t * offsets,void * p)3630 static void finish_ffi_call(ffi_cif *cif, void *c_func, intptr_t cfoff,
3631                             int nargs, GC_CAN_IGNORE ForeignAny *ivals, void **avalues,
3632                             intptr_t *offsets, void *p)
3633 /* Complete an FFI call in non-GC mode, so that arguments won't move around: */
3634   XFORM_SKIP_PROC
3635 {
3636   int i;
3637   for (i=0; i<nargs; i++) {
3638     if ((avalues[i] == NULL) && !offsets[i]) /* if this was a non-pointer... */
3639       avalues[i] = &(ivals[i]); /* ... set the avalues pointer */
3640     else if ((ivals[i].x_fixnum != FOREIGN_struct)
3641              && (ivals[i].x_fixnum != FOREIGN_union)) { /* if *not* a struct... */
3642       /* ... set the ivals pointer (pointer type doesn't matter) and avalues */
3643       ivals[i].x_pointer = avalues[i];
3644       avalues[i] = &(ivals[i]);
3645     } else if (offsets[i]) {
3646       /* struct argument has an offset */
3647       avalues[i] = (char *)avalues[i] + offsets[i];
3648     }
3649     /* Otherwise it was a struct pointer, and avalues[i] is already fine. */
3650     /* Add offset, if any: */
3651     if (offsets[i] != 0) {
3652       ivals[i].x_pointer = (char *)ivals[i].x_pointer + offsets[i];
3653     }
3654   }
3655   /* Finally, call the function */
3656   ffi_call(cif, (VoidFun)W_OFFSET(c_func, cfoff), p, avalues);
3657 }
3658 
finish_ffi_call_handle_exn(ffi_cif * cif,void * c_func,intptr_t cfoff,int nargs,GC_CAN_IGNORE ForeignAny * ivals,void ** avalues,intptr_t * offsets,void * p,Scheme_Object * lock)3659 static void finish_ffi_call_handle_exn(ffi_cif *cif, void *c_func, intptr_t cfoff,
3660                                        int nargs, GC_CAN_IGNORE ForeignAny *ivals, void **avalues,
3661                                        intptr_t *offsets, void *p,
3662                                        Scheme_Object *lock)
3663 {
3664   mz_jmp_buf * volatile save, fresh;
3665 
3666   save = scheme_current_thread->error_buf;
3667   scheme_current_thread->error_buf = &fresh;
3668 
3669   if (scheme_setjmp(scheme_error_buf)) {
3670     if (SCHEME_TRUEP(lock))
3671       release_ffi_lock(lock);
3672     scheme_end_in_scheduler();
3673     scheme_longjmp(*save, 1);
3674   } else {
3675     finish_ffi_call(cif, c_func, cfoff,
3676                     nargs, ivals, avalues,
3677                     offsets, p);
3678   }
3679 
3680   scheme_current_thread->error_buf = save;
3681 }
3682 
ffi_do_call(int argc,Scheme_Object * argv[],Scheme_Object * self)3683 static Scheme_Object *ffi_do_call(int argc, Scheme_Object *argv[], Scheme_Object *self)
3684 /* data := {name, c-function, itypes, otype, cif} */
3685 {
3686   Scheme_Object *data = SCHEME_PRIM_CLOSURE_ELS(self)[0];
3687   int curried = !SCHEME_VEC_ELS(data)[1] && !SCHEME_INT_VAL(SCHEME_VEC_ELS(data)[5]);
3688   const char    *name = ((Scheme_Primitive_Closure *)self)->p.name;
3689   void          *c_func = (curried
3690                            ? (void*)SCHEME_PRIM_CLOSURE_ELS(self)[1]
3691                            : (void*)(SCHEME_VEC_ELS(data)[1]));
3692   Scheme_Object *itypes = SCHEME_VEC_ELS(data)[2];
3693   Scheme_Object *otype  = SCHEME_VEC_ELS(data)[3];
3694   Scheme_Object *base;
3695   ffi_cif       *cif    = (ffi_cif*)(SCHEME_VEC_ELS(data)[4]);
3696   intptr_t      cfoff   = (curried
3697                            ? SCHEME_INT_VAL(SCHEME_PRIM_CLOSURE_ELS(self)[2])
3698                            : SCHEME_INT_VAL(SCHEME_VEC_ELS(data)[5]));
3699   int           save_errno = SCHEME_INT_VAL(SCHEME_VEC_ELS(data)[6]);
3700   Scheme_Object *lock = SCHEME_VEC_ELS(data)[7];
3701   int           callback_exns = SCHEME_TRUEP(SCHEME_VEC_ELS(data)[8]);
3702 #ifdef MZ_USE_PLACES
3703   int           orig_place = SCHEME_TRUEP(SCHEME_VEC_ELS(data)[9]);
3704 #endif
3705   int           nargs /* = cif->nargs, after checking cif */;
3706   /* When the foreign function is called, we need an array (ivals) of nargs
3707    * ForeignAny objects to store the actual C values that are created, and we
3708    * need another array (avalues) for the pointers to these values (this is
3709    * what libffi actually uses).  To make things more fun, ForeignAny is
3710    * problematic for the precise GC, since it is sometimes a pointer and
3711    * sometime not.  To deal with this, while converting argv objects into
3712    * ivals, scheme_to_c will save pointer values in avalues, so the GC can,
3713    * ignore ivals -- just before we reach the actual call, avalues is
3714    * overwritten, but from that point on it is all C code so there is no
3715    * problem.  Hopefully.
3716    * (Things get complicated if the C call can involve GC (usually due to a
3717    * Racket callback), but then the programmer need to arrange for pointers
3718    * that cannot move.  Because of all this, the *only* array that should not
3719    * be ignored by the GC is avalues.)
3720    */
3721   ForeignAny *ivals;
3722   void **avalues, *p, *newp;
3723   GC_CAN_IGNORE ForeignAny stack_ivals[MAX_QUICK_ARGS], oval;
3724   void *stack_avalues[MAX_QUICK_ARGS];
3725   intptr_t stack_offsets[MAX_QUICK_ARGS];
3726   int i;
3727   intptr_t basetype, offset, *offsets;
3728 #ifdef MZ_USE_PLACES
3729   if (orig_place && (scheme_current_place_id == 0) && !MZ_USE_FFIPOLL_COND)
3730     orig_place = 0;
3731 #endif
3732   if (!cif) {
3733     scheme_signal_error("ffi-call: foreign-function reference was already finalized%s%s",
3734                         name ? "\n  name: " : "",
3735                         name ? name : "");
3736     return NULL;
3737   }
3738   nargs =  cif->nargs;
3739   if ((nargs <= MAX_QUICK_ARGS)) {
3740     ivals   = stack_ivals;
3741     avalues = stack_avalues;
3742     offsets = stack_offsets;
3743   } else {
3744     ivals   = scheme_malloc_atomic_allow_interior(nargs * sizeof(ForeignAny));
3745     avalues = scheme_malloc(nargs * sizeof(void*));
3746     offsets = scheme_malloc_atomic(nargs * sizeof(intptr_t));
3747   }
3748   /* iterate on input values and types */
3749   for (i=0; i<nargs; i++, itypes=SCHEME_CDR(itypes)) {
3750     /* convert argv[i] according to current itype */
3751     offset = 0;
3752     p = SCHEME2C(name, SCHEME_CAR(itypes), &(ivals[i]), 0, argv[i], &basetype,
3753                  &offset, 0);
3754     if ((p != NULL) || offset) {
3755       avalues[i] = p;
3756       ivals[i].x_fixnum = basetype; /* remember the base type */
3757     } else {
3758       avalues[i] = NULL;
3759     }
3760     offsets[i] = offset;
3761   }
3762   base = get_ctype_base(otype); /* verified below, so cannot be NULL */
3763   /* If this is a struct return value, then need to malloc in any case, even if
3764    * the size is smaller than ForeignAny, because this value will be
3765    * returned. */
3766   if ((CTYPE_PRIMLABEL(base) == FOREIGN_struct)
3767       || (CTYPE_PRIMLABEL(base) == FOREIGN_union)) {
3768     /* need to have p be a pointer that is invisible to the GC */
3769     p = malloc(CTYPE_PRIMTYPE(base)->size);
3770     {
3771       Scheme_Malloc_Proc mf;
3772       mf = ctype_allocator(base);
3773       newp = mf(CTYPE_PRIMTYPE(base)->size);
3774     }
3775   } else {
3776     p = &oval;
3777     newp = NULL;
3778   }
3779 
3780   if (SCHEME_TRUEP(lock))
3781     wait_ffi_lock(lock);
3782 
3783 #ifdef MZ_USE_PLACES
3784   if (orig_place)
3785     ffi_call_in_orig_place(cif, c_func, cfoff,
3786                            nargs, ivals, avalues,
3787                            offsets, p);
3788   else
3789 #endif
3790     {
3791       if (callback_exns)
3792         finish_ffi_call_handle_exn(cif, c_func, cfoff,
3793                                    nargs, ivals, avalues,
3794                                    offsets, p, lock);
3795       else
3796         finish_ffi_call(cif, c_func, cfoff,
3797                         nargs, ivals, avalues,
3798                         offsets, p);
3799     }
3800 
3801   if (SCHEME_TRUEP(lock))
3802     release_ffi_lock(lock);
3803 
3804   /* Use `data' to make sure it's kept alive (as far as the GC is concerned)
3805      until the foreign call returns: */
3806   if ((void*)data == (void*)scheme_true)
3807     scheme_signal_error("dummy test succeeded!?");
3808 
3809   if (save_errno != 0) save_errno_values(save_errno);
3810   ivals = NULL; /* no need now to hold on to this */
3811   for (i=0; i<nargs; i++) { avalues[i] = NULL; } /* no need for these refs */
3812   avalues = NULL;
3813   switch (CTYPE_PRIMLABEL(base)) {
3814   case FOREIGN_struct:
3815   case FOREIGN_union:
3816     memcpy(newp, p, CTYPE_PRIMTYPE(base)->size);
3817     free(p);
3818     p = newp;
3819     break;
3820   case FOREIGN_array:
3821     /* array as result is treated as a pointer, so
3822        adjust `p' to make C2SCHEME work right */
3823     p = *(void **)p;
3824     break;
3825   }
3826   return C2SCHEME(NULL, otype, p, 0, 1, 1);
3827 }
3828 
ffi_do_call_k()3829 static Scheme_Object *ffi_do_call_k()
3830 {
3831   Scheme_Thread *p = scheme_current_thread;
3832   Scheme_Object **argv, *self;
3833 
3834   argv = (Scheme_Object **)p->ku.k.p1;
3835   self = (Scheme_Object *)p->ku.k.p2;
3836 
3837   p->ku.k.p1 = NULL;
3838   p->ku.k.p2 = NULL;
3839 
3840   return ffi_do_call(p->ku.k.i1, argv, self);
3841 }
3842 
ffi_do_call_after_stack_check(int argc,Scheme_Object * argv[],Scheme_Object * self)3843 static Scheme_Object *ffi_do_call_after_stack_check(int argc, Scheme_Object *argv[], Scheme_Object *self)
3844 {
3845   /* Make sure we have an extra-comfortable amount of space on the
3846      stack before calling into foreign code: */
3847   if (!scheme_no_stack_overflow && scheme_is_stack_too_shallow()) {
3848     Scheme_Thread *p = scheme_current_thread;
3849     p->ku.k.i1 = argc;
3850     p->ku.k.p1 = argv;
3851     p->ku.k.p2 = self;
3852     return scheme_handle_stack_overflow(ffi_do_call_k);
3853   } else
3854     return ffi_do_call(argc, argv, self);
3855 }
3856 
3857 /* see below */
free_fficall_data(void * data,void * p)3858 void free_fficall_data(void *data, void *p)
3859 {
3860   SCHEME_VEC_ELS(data)[4] = NULL;
3861   free(((ffi_cif*)p)->arg_types);
3862   free(p);
3863 }
3864 
3865 static Scheme_Object *ffi_name = NULL;
3866 
make_ffi_call_from_curried(int argc,Scheme_Object * argv[],Scheme_Object * self)3867 static Scheme_Object *make_ffi_call_from_curried(int argc, Scheme_Object *argv[], Scheme_Object *self)
3868 {
3869   Scheme_Object *data = SCHEME_PRIM_CLOSURE_ELS(self)[0];
3870   Scheme_Object *a[3], *name, *itypes, *obj, *cp;
3871   const char *name_str;
3872   intptr_t ooff;
3873   int nargs;
3874 
3875   cp = unwrap_cpointer_property(argv[0]);
3876   if (!SCHEME_FFIANYPTRP(cp))
3877     scheme_wrong_contract("make-ffi-call", "(or/c ffi-obj? cpointer?)", 0, argc, argv);
3878   obj = SCHEME_FFIANYPTR_VAL(cp);
3879   ooff = SCHEME_FFIANYPTR_OFFSET(cp);
3880   if ((obj == NULL) && (ooff == 0))
3881     scheme_wrong_contract("make-ffi-call", NON_NULL_CPOINTER, 0, argc, argv);
3882 
3883   name = SCHEME_VEC_ELS(data)[0];
3884   if (SCHEME_FFIOBJP(cp))
3885     name_str = ((ffi_obj_struct*)(cp))->name;
3886   else
3887     name_str = SCHEME_BYTE_STR_VAL(name);
3888 
3889   itypes = SCHEME_VEC_ELS(data)[2];
3890 
3891   nargs = scheme_proper_list_length(itypes);
3892 
3893   a[0] = data;
3894   a[1] = obj;
3895   a[2] = scheme_make_integer_value(ooff);
3896 
3897   return scheme_make_prim_closure_w_arity(ffi_do_call_after_stack_check,
3898                                           3, a,
3899                                           name_str,
3900                                           nargs, nargs);
3901 
3902 }
3903 
ffi_call_or_curry(const char * who,int curry,int argc,Scheme_Object ** argv)3904 static Scheme_Object *ffi_call_or_curry(const char *who, int curry, int argc, Scheme_Object **argv) {
3905 # define ARGPOS(n) ((n) - (curry ? 1 : 0))
3906   Scheme_Object *itypes = argv[ARGPOS(1)];
3907   Scheme_Object *otype  = argv[ARGPOS(2)];
3908   Scheme_Object *obj, *data, *p, *base, *cp, *name, *a[1];
3909   ffi_abi abi;
3910   int varargs_after;
3911   intptr_t ooff;
3912   GC_CAN_IGNORE ffi_type *rtype, **atypes;
3913   GC_CAN_IGNORE ffi_cif *cif;
3914   int i, nargs, save_errno, callback_exns;
3915   Scheme_Object *lock = scheme_false;
3916   Scheme_Performance_State perf_state;
3917 # ifdef MZ_USE_PLACES
3918   int orig_place = MZ_USE_FFIPOLL_COND;
3919 # define FFI_CALL_VEC_SIZE 10
3920 # else /* MZ_USE_PLACES undefined */
3921 # define FFI_CALL_VEC_SIZE 9
3922 # endif /* MZ_USE_PLACES */
3923   scheme_performance_record_start(&perf_state);
3924   if (!curry) {
3925     cp = unwrap_cpointer_property(argv[ARGPOS(0)]);
3926     if (!SCHEME_FFIANYPTRP(cp))
3927       scheme_wrong_contract(who, "(or/c ffi-obj? cpointer?)", ARGPOS(0), argc, argv);
3928     obj = SCHEME_FFIANYPTR_VAL(cp);
3929     ooff = SCHEME_FFIANYPTR_OFFSET(cp);
3930     if ((obj == NULL) && (ooff == 0))
3931       scheme_wrong_contract(who, NON_NULL_CPOINTER, 0, argc, argv);
3932   } else {
3933     cp = NULL;
3934     obj = NULL;
3935     ooff = 0;
3936   }
3937   nargs = scheme_proper_list_length(itypes);
3938   if (nargs < 0)
3939     scheme_wrong_contract(who, "list?", ARGPOS(1), argc, argv);
3940   if (NULL == (base = get_ctype_base(otype)))
3941     scheme_wrong_contract(who, "ctype?", ARGPOS(2), argc, argv);
3942   rtype = CTYPE_ARG_PRIMTYPE(base);
3943   abi = GET_ABI(who, ARGPOS(3));
3944   if (argc > ARGPOS(4)) {
3945     save_errno = -1;
3946     if (SCHEME_FALSEP(argv[ARGPOS(4)]))
3947       save_errno = 0;
3948     else if (SCHEME_SYMBOLP(argv[ARGPOS(4)])
3949              && !SCHEME_SYM_WEIRDP(argv[ARGPOS(4)])) {
3950       if (!strcmp(SCHEME_SYM_VAL(argv[ARGPOS(4)]), "posix"))
3951         save_errno = 1;
3952       else if (!strcmp(SCHEME_SYM_VAL(argv[ARGPOS(4)]), "windows"))
3953         save_errno = 2;
3954     }
3955     if (save_errno == -1) {
3956       scheme_wrong_contract(who, "(or/c 'posix 'windows #f)", ARGPOS(4), argc, argv);
3957     }
3958   } else
3959     save_errno = 0;
3960 # if defined(MZ_USE_PLACES) && !defined(MZ_USE_FFIPOLL)
3961   if (argc > ARGPOS(5)) orig_place = SCHEME_TRUEP(argv[ARGPOS(5)]);
3962   else orig_place = 0;
3963 # endif /* defined(MZ_USE_PLACES) && !defined(MZ_USE_FFIPOLL) */
3964   if (argc > ARGPOS(6)) {
3965     if (!SCHEME_FALSEP(argv[ARGPOS(6)])) {
3966       if (!SCHEME_CHAR_STRINGP(argv[ARGPOS(6)]))
3967         scheme_wrong_contract(who, "(or/c string? #f)", ARGPOS(6), argc, argv);
3968       lock = name_to_ffi_lock(scheme_char_string_to_byte_string(argv[ARGPOS(6)]));
3969     }
3970   }
3971   /* ARGPOS(7) is `blocking?`, but we don't use that */
3972   if (argc > ARGPOS(8)) {
3973     varargs_after = extract_varargs_after(who, argc, argv, ARGPOS(8), nargs);
3974   } else
3975     varargs_after = -1;
3976   if (argc > ARGPOS(9))
3977     callback_exns = SCHEME_TRUEP(argv[ARGPOS(9)]);
3978   else
3979     callback_exns = 0;
3980 
3981   if (cp && SCHEME_FFIOBJP(cp))
3982     name = scheme_make_byte_string(((ffi_obj_struct*)(cp))->name);
3983   else
3984     name = ffi_name;
3985   atypes = malloc(nargs * sizeof(ffi_type*));
3986   for (i=0, p=itypes; i<nargs; i++, p=SCHEME_CDR(p)) {
3987     if (NULL == (base = get_ctype_base(SCHEME_CAR(p))))
3988       scheme_wrong_contract(who, "(listof ctype?)", ARGPOS(1), argc, argv);
3989     if (CTYPE_PRIMLABEL(base) == FOREIGN_void)
3990       wrong_void(who, SCHEME_CAR(p), 1, ARGPOS(1), argc, argv);
3991     atypes[i] = CTYPE_ARG_PRIMTYPE(base);
3992   }
3993   cif = malloc(sizeof(ffi_cif));
3994   if (varargs_after == -1) {
3995     if (ffi_prep_cif(cif, abi, nargs, rtype, atypes) != FFI_OK)
3996       scheme_signal_error("internal error: ffi_prep_cif did not return FFI_OK");
3997   } else {
3998     if (ffi_prep_cif_var(cif, abi, varargs_after, nargs, rtype, atypes) != FFI_OK)
3999       scheme_signal_error("internal error: ffi_prep_cif_var did not return FFI_OK");
4000   }
4001   data = scheme_make_vector(FFI_CALL_VEC_SIZE, NULL);
4002   SCHEME_VEC_ELS(data)[0] = name;
4003   SCHEME_VEC_ELS(data)[1] = obj;
4004   SCHEME_VEC_ELS(data)[2] = itypes;
4005   SCHEME_VEC_ELS(data)[3] = otype;
4006   SCHEME_VEC_ELS(data)[4] = (Scheme_Object*)cif;
4007   SCHEME_VEC_ELS(data)[5] = scheme_make_integer(ooff);
4008   SCHEME_VEC_ELS(data)[6] = scheme_make_integer(save_errno);
4009   SCHEME_VEC_ELS(data)[7] = lock;
4010   SCHEME_VEC_ELS(data)[8] = (callback_exns ? scheme_true : scheme_false);
4011 # ifdef MZ_USE_PLACES
4012   SCHEME_VEC_ELS(data)[9] = (orig_place ? scheme_true : scheme_false);
4013 # endif /* MZ_USE_PLACES */
4014   scheme_register_finalizer(data, free_fficall_data, cif, NULL, NULL);
4015   a[0] = data;
4016 
4017   scheme_performance_record_end("comp-ffi-call", &perf_state);
4018 
4019   if (curry) {
4020     return scheme_make_prim_closure_w_arity(make_ffi_call_from_curried,
4021                                             1, a,
4022                                             "make-ffi-call",
4023                                             1, 1);
4024   } else {
4025     return scheme_make_prim_closure_w_arity(ffi_do_call_after_stack_check,
4026                                             1, a,
4027                                             SCHEME_BYTE_STR_VAL(name),
4028                                             nargs, nargs);
4029   }
4030 #undef ARGPOS
4031 }
4032 
4033 /* (ffi-call ffi-obj in-types out-type [abi save-errno? orig-place? lock-name blocking? varargs-after exns?]) -> (in-types -> out-value) */
4034 /* the real work is done by ffi_do_call above */
4035 #define MYNAME "ffi-call"
foreign_ffi_call(int argc,Scheme_Object * argv[])4036 static Scheme_Object *foreign_ffi_call(int argc, Scheme_Object *argv[])
4037 {
4038   return ffi_call_or_curry(MYNAME, 0, argc, argv);
4039 }
4040 #undef MYNAME
4041 
4042 /* (ffi-call-maker in-types out-type [abi save-errno? orig-place? lock-name blocking? varargs-after exns?]) -> (ffi->obj -> (in-types -> out-value)) */
4043 /* Curried version of `ffi-call` */
4044 #define MYNAME "ffi-call-maker"
foreign_ffi_call_maker(int argc,Scheme_Object * argv[])4045 static Scheme_Object *foreign_ffi_call_maker(int argc, Scheme_Object *argv[])
4046 {
4047   return ffi_call_or_curry(MYNAME, 1, argc, argv);
4048 }
4049 #undef MYNAME
4050 
4051 /*****************************************************************************/
4052 /* Racket callbacks */
4053 
4054 typedef void (*ffi_callback_t)(ffi_cif* cif, void* resultp, void** args, void *userdata);
4055 
extract_ffi_callback(void * userdata)4056 static ffi_callback_struct *extract_ffi_callback(void *userdata)
4057   XFORM_SKIP_PROC
4058 {
4059   ffi_callback_struct *data;
4060 
4061 #ifdef MZ_PRECISE_GC
4062   {
4063     void *tmp;
4064     tmp  = *((void**)userdata);
4065     data = (ffi_callback_struct *)SCHEME_WEAK_BOX_VAL(tmp);
4066     if (data == NULL) scheme_signal_error("callback lost");
4067   }
4068 #else
4069   data = (ffi_callback_struct *)userdata;
4070 #endif
4071 
4072   return data;
4073 }
4074 
ffi_do_callback(ffi_cif * cif,void * resultp,void ** args,void * userdata)4075 static void ffi_do_callback(ffi_cif* cif, void* resultp, void** args, void *userdata)
4076 {
4077   ffi_callback_struct *data;
4078   Scheme_Object *argv_stack[MAX_QUICK_ARGS];
4079   int argc = cif->nargs, i;
4080   Scheme_Object **argv, *p, *v, *t;
4081 
4082   data = extract_ffi_callback(userdata);
4083 
4084   if (argc <= MAX_QUICK_ARGS)
4085     argv = argv_stack;
4086   else
4087     argv = scheme_malloc(argc * sizeof(Scheme_Object*));
4088   if (data->sync && !SCHEME_PROCP(data->sync))
4089     scheme_start_in_scheduler();
4090   for (i=0, p=data->itypes; i<argc; i++, p=SCHEME_CDR(p)) {
4091     t = SCHEME_CAR(p);
4092     if (CTYPE_PRIMLABEL(get_ctype_base(t)) == FOREIGN_array) {
4093       /* array as argument is treated as a pointer */
4094       v = C2SCHEME(NULL, t, *(void **)(args[i]), 0, 0, 0);
4095     } else
4096       v = C2SCHEME(NULL, t, args[i], 0, 0, 0);
4097     argv[i] = v;
4098   }
4099   p = _scheme_apply(data->proc, argc, argv);
4100   SCHEME2C("callback result", data->otype, resultp, 0, p, NULL, NULL, 1);
4101   if (data->sync && !SCHEME_PROCP(data->sync))
4102     scheme_end_in_scheduler();
4103 }
4104 
4105 #ifdef MZ_USE_MZRT
4106 
4107 /* When OS-level thread support is available, support callbacks
4108    in foreign threads that are executed on the main Racket thread. */
4109 
4110 typedef struct Queued_Callback {
4111   ffi_cif* cif;
4112   void* resultp;
4113   void** args;
4114   void *userdata;
4115   mzrt_sema *sema;
4116   int called;
4117   struct Queued_Callback *next;
4118 } Queued_Callback;
4119 
4120 typedef struct FFI_Sync_Queue {
4121   Queued_Callback *callbacks; /* malloc()ed list */
4122   mzrt_mutex *lock;
4123   mzrt_os_thread_id orig_thread;
4124   void *sig_hand;
4125 } FFI_Sync_Queue;
4126 
4127 THREAD_LOCAL_DECL(static struct FFI_Sync_Queue *ffi_sync_queue);
4128 
callback_thunk(void * _qc,int argc,Scheme_Object * argv[])4129 static Scheme_Object *callback_thunk(void *_qc, int argc, Scheme_Object *argv[])
4130 {
4131   Queued_Callback *qc = (Queued_Callback *)_qc;
4132 
4133   if (qc->called)
4134     scheme_raise_exn(MZEXN_FAIL_CONTRACT,
4135                      "callback thunk for synchronization has already been called");
4136   qc->called = 1;
4137 
4138   ffi_do_callback(qc->cif, qc->resultp, qc->args, qc->userdata);
4139 
4140   mzrt_sema_post(qc->sema);
4141 
4142   return scheme_void;
4143 }
4144 
check_foreign_work(int check_for_in_original)4145 static void check_foreign_work(int check_for_in_original)
4146 # ifdef MZ_USE_FFIPOLL
4147   XFORM_SKIP_PROC
4148 # endif /* MZ_USE_FFIPOLL */
4149 {
4150   GC_CAN_IGNORE Queued_Callback *qc;
4151   ffi_callback_struct *data;
4152   Scheme_Object *a[1], *proc;
4153 
4154 #ifdef MZ_USE_FFIPOLL
4155   /* We don't currently support callbacks from C to Racket in FFIPOLL
4156      mode, and this function is not allowed to touch the GC or Racket
4157      in that mode. */
4158 #else
4159   if (ffi_sync_queue) {
4160     do {
4161       mzrt_mutex_lock(ffi_sync_queue->lock);
4162       qc = ffi_sync_queue->callbacks;
4163       if (qc)
4164         ffi_sync_queue->callbacks = qc->next;
4165       mzrt_mutex_unlock(ffi_sync_queue->lock);
4166 
4167       if (qc) {
4168         qc->next = NULL;
4169 
4170         data = extract_ffi_callback(qc->userdata);
4171 
4172         proc = scheme_make_closed_prim_w_arity(callback_thunk, (void *)qc,
4173                                                "callback-thunk", 0, 0);
4174         a[0] = proc;
4175 
4176         proc = data->sync;
4177         if (SCHEME_BOXP(proc)) proc = SCHEME_BOX_VAL(proc);
4178 
4179         scheme_start_in_scheduler();
4180         _scheme_apply(proc, 1, a);
4181         scheme_end_in_scheduler();
4182       }
4183 
4184     } while (qc);
4185   }
4186 #endif
4187 
4188 #ifdef MZ_USE_PLACES
4189   if (check_for_in_original && ((scheme_current_place_id == 0) || MZ_USE_FFIPOLL_COND) && orig_place_mutex) {
4190     FFI_Orig_Place_Call *todo;
4191     void *sh;
4192 
4193     while (1) {
4194       mzrt_mutex_lock(orig_place_mutex);
4195       todo = orig_place_calls_tail;
4196       if (todo) {
4197         orig_place_calls_tail = todo->prev;
4198         if (todo->prev)
4199           todo->prev->next = NULL;
4200         else
4201           orig_place_calls = NULL;
4202         todo->needs_queue = 0;
4203       }
4204       mzrt_mutex_unlock(orig_place_mutex);
4205 
4206       if (todo) {
4207         finish_ffi_call(todo->cif, todo->c_func, todo->cfoff,
4208                         todo->nargs, todo->ivals, todo->avalues,
4209                         todo->offsets, todo->p);
4210         mzrt_mutex_lock(orig_place_mutex);
4211         sh = todo->signal_handle;
4212         todo->signal_handle = NULL; /* indicates "done" */
4213         scheme_signal_received_at(sh);
4214         mzrt_mutex_unlock(orig_place_mutex);
4215       } else
4216         break;
4217     }
4218   }
4219 #endif
4220 }
4221 
scheme_check_foreign_work(void)4222 void scheme_check_foreign_work(void)
4223 # ifdef MZ_USE_FFIPOLL
4224   XFORM_SKIP_PROC
4225 # endif /* MZ_USE_FFIPOLL */
4226 {
4227   check_foreign_work(1);
4228 }
4229 
4230 #endif
4231 
ffi_queue_callback(ffi_cif * cif,void * resultp,void ** args,void * userdata)4232 static void ffi_queue_callback(ffi_cif* cif, void* resultp, void** args, void *userdata)
4233   XFORM_SKIP_PROC
4234 {
4235 #ifdef MZ_USE_MZRT
4236   /* This function must not refer to any GCable address, not even
4237      temporarily, because a GC may occur concurrent to this
4238      function if it's in another thread. */
4239   FFI_Sync_Queue *queue;
4240   void **data = (void **)userdata;
4241 
4242   queue = (FFI_Sync_Queue *)(data)[1];
4243   userdata = (data)[0];
4244 
4245   if (queue->orig_thread != mz_proc_os_thread_self()) {
4246     if (data[2]) {
4247       /* constant result */
4248       memcpy(resultp, data[2], (intptr_t)data[3]);
4249       return;
4250     } else {
4251       /* queue  a callback and wait: */
4252       Queued_Callback *qc;
4253       mzrt_sema *sema;
4254 
4255       mzrt_sema_create(&sema, 0);
4256 
4257       qc = (Queued_Callback *)malloc(sizeof(Queued_Callback));
4258       qc->cif = cif;
4259       qc->resultp = resultp;
4260       qc->args = args;
4261       qc->userdata = userdata;
4262       qc->sema = sema;
4263       qc->called = 0;
4264 
4265       mzrt_mutex_lock(queue->lock);
4266       qc->next = queue->callbacks;
4267       queue->callbacks = qc;
4268       mzrt_mutex_unlock(queue->lock);
4269       scheme_signal_received_at(queue->sig_hand);
4270 
4271       /* wait for the callback to be invoked in the main thread */
4272       mzrt_sema_wait(sema);
4273 
4274       mzrt_sema_destroy(sema);
4275       free(qc);
4276       return;
4277     }
4278   }
4279 #endif
4280 
4281   ffi_do_callback(cif, resultp, args, userdata);
4282 }
4283 
4284 /* see ffi-callback below */
4285 typedef struct closure_and_cif_struct {
4286   ffi_closure          closure;
4287   ffi_cif              cif;
4288 #ifdef MZ_PRECISE_GC
4289   struct immobile_box *data;
4290 #else
4291   void                *data;
4292 #endif
4293 } closure_and_cif;
4294 
4295 /* free the above */
free_cl_cif_args(void * ignored,void * p)4296 static void free_cl_cif_args(void *ignored, void *p)
4297 {
4298   /*
4299   scheme_warning("Releasing cl+cif+args %V %V (%d)",
4300                  ignored,
4301                  (((closure_and_cif*)p)->data),
4302                  SAME_OBJ(ignored,(((closure_and_cif*)p)->data)));
4303   */
4304 #ifdef MZ_PRECISE_GC
4305   GC_free_immobile_box((void**)(((closure_and_cif*)p)->data));
4306 #endif
4307   scheme_free_code(p);
4308 }
4309 
4310 #ifdef MZ_USE_MZRT
free_cl_cif_queue_args(void * ignored,void * p)4311 static void free_cl_cif_queue_args(void *ignored, void *p)
4312 {
4313   void *data = ((closure_and_cif*)p)->data, *constant_result;
4314   void **q = (void **)data;
4315   data = q[0];
4316   constant_result = q[2];
4317   free(q);
4318   if (constant_result) free(constant_result);
4319 #ifdef MZ_PRECISE_GC
4320   GC_free_immobile_box((void**)data);
4321 #endif
4322   scheme_free_code(p);
4323 }
4324 #endif
4325 
4326 /* In `curry` mode, just check arguments */
ffi_callback_or_curry(const char * who,int curry,int argc,Scheme_Object ** argv)4327 static Scheme_Object *ffi_callback_or_curry(const char *who, int curry, int argc, Scheme_Object **argv) {
4328 # define ARGPOS(n) ((n) - (curry ? 1 : 0))
4329   ffi_callback_struct *data;
4330   Scheme_Object *itypes = argv[ARGPOS(1)];
4331   Scheme_Object *otype = argv[ARGPOS(2)];
4332   Scheme_Object *sync;
4333   Scheme_Object *p, *base;
4334   ffi_abi abi;
4335   int is_atomic;
4336   int nargs, i, varargs_after;
4337   ffi_status ffi_ok;
4338   /* ffi_closure objects are problematic when used with a moving GC.  The
4339    * problem is that memory that is GC-visible can move at any time.  The
4340    * solution is to use an immobile-box, which an immobile pointer (in a simple
4341    * malloced block), which points to the ffi_callback_struct that contains the
4342    * relevant Racket call details.  Another minor complexity is that an
4343    * immobile box serves as a reference for the GC, which means that nothing
4344    * will ever get collected: and the solution for this is to stick a weak-box
4345    * in the chain.  Users need to be aware of GC issues, and need to keep a
4346    * reference to the callback object to avoid releasing the whole thing --
4347    * when that reference is lost, the ffi_callback_struct will be GCed, and a
4348    * finalizer will free() the malloced memory.  Everything on the malloced
4349    * part is allocated in one block, to make it easy to free.  The final layout
4350    * of the various objects is:
4351    *
4352    * <<======malloc======>> : <<===========scheme_malloc===============>>
4353    *                        :
4354    *    ffi_closure <------------------------\
4355    *      |  |              :                |
4356    *      |  |              :                |
4357    *      |  \--> immobile ----> weak        |
4358    *      |         box     :    box         |
4359    *      |                 :     |          |
4360    *      |                 :     |          |
4361    *      |                 :     \--> ffi_callback_struct
4362    *      |                 :               |  |
4363    *      V                 :               |  \-----> Racket Closure
4364    *     cif ---> atypes    :               |
4365    *                        :               \--------> input/output types
4366    */
4367   GC_CAN_IGNORE ffi_type *rtype, **atypes;
4368   GC_CAN_IGNORE ffi_cif *cif;
4369   GC_CAN_IGNORE ffi_closure *cl;
4370   GC_CAN_IGNORE closure_and_cif *cl_cif_args;
4371   GC_CAN_IGNORE ffi_callback_t do_callback;
4372   GC_CAN_IGNORE void *callback_data;
4373   Scheme_Performance_State perf_state;
4374 # ifdef MZ_USE_MZRT
4375   int keep_queue = 0;
4376   void *constant_reply = NULL;
4377   int constant_reply_size = 0;
4378 # endif /* MZ_USE_MZRT */
4379 
4380   if (!curry && !SCHEME_PROCP(argv[ARGPOS(0)]))
4381     scheme_wrong_contract(who, "procedure?", ARGPOS(0), argc, argv);
4382   nargs = scheme_proper_list_length(itypes);
4383   if (nargs < 0)
4384     scheme_wrong_contract(who, "list?", ARGPOS(1), argc, argv);
4385   if (NULL == (base = get_ctype_base(otype)))
4386     scheme_wrong_contract(who, "ctype?", ARGPOS(2), argc, argv);
4387   rtype = CTYPE_ARG_PRIMTYPE(base);
4388   abi = GET_ABI(who, ARGPOS(3));
4389   is_atomic = ((argc > ARGPOS(4)) && SCHEME_TRUEP(argv[ARGPOS(4)]));
4390   sync = (is_atomic ? scheme_true : NULL);
4391   if ((argc > ARGPOS(5))
4392       && !SCHEME_BOXP(argv[ARGPOS(5)])
4393       && !scheme_check_proc_arity2(NULL, 1, ARGPOS(5), argc, argv, 1))
4394     scheme_wrong_contract(who, "(or/c #f (procedure-arity-includes/c 0) box?)", ARGPOS(5), argc, argv);
4395   if (argc > ARGPOS(6))
4396     varargs_after = extract_varargs_after(who, argc, argv, ARGPOS(6), nargs);
4397   else
4398     varargs_after = -1;
4399 
4400   if (curry) {
4401     /* all checks are done */
4402     return NULL;
4403   }
4404 
4405   scheme_performance_record_start(&perf_state);
4406 
4407   if (((argc > ARGPOS(5)) && SCHEME_TRUEP(argv[ARGPOS(5)]))) {
4408 #   ifdef MZ_USE_MZRT
4409     if (!ffi_sync_queue) {
4410       mzrt_os_thread_id tid;
4411       void *sig_hand;
4412 
4413       ffi_sync_queue = (FFI_Sync_Queue *)malloc(sizeof(FFI_Sync_Queue));
4414       tid = mz_proc_os_thread_self();
4415       ffi_sync_queue->orig_thread = tid;
4416       mzrt_mutex_create(&ffi_sync_queue->lock);
4417       sig_hand = scheme_get_signal_handle();
4418       ffi_sync_queue->sig_hand = sig_hand;
4419       ffi_sync_queue->callbacks = NULL;
4420     }
4421     if (SCHEME_BOXP(argv[ARGPOS(5)])) {
4422       /* when called in a foreign thread, return a constant */
4423       constant_reply_size = ctype_sizeof(otype);
4424       if (!constant_reply_size && SCHEME_VOIDP(SCHEME_BOX_VAL(argv[ARGPOS(5)]))) {
4425         /* void result */
4426         constant_reply = scheme_malloc_atomic(1);
4427       } else {
4428         /* non-void result */
4429         constant_reply = scheme_malloc_atomic(constant_reply_size);
4430         SCHEME2C(who, otype, constant_reply, 0, SCHEME_BOX_VAL(argv[ARGPOS(5)]), NULL, NULL, 0);
4431       }
4432     } else {
4433       /* when called in a foreign thread, queue a reply back here */
4434       sync = argv[ARGPOS(5)];
4435       if (is_atomic) sync = scheme_box(sync);
4436       constant_reply = NULL;
4437       constant_reply_size = 0;
4438     }
4439     keep_queue = 1;
4440 #   endif /* MZ_USE_MZRT */
4441     do_callback = ffi_queue_callback;
4442   } else
4443     do_callback = ffi_do_callback;
4444 
4445   /* malloc space for everything needed, so a single free gets rid of this */
4446   cl_cif_args = scheme_malloc_code(sizeof(closure_and_cif) + nargs*sizeof(ffi_cif*));
4447   scheme_thread_code_start_write();
4448   cl = &(cl_cif_args->closure); /* cl is the same as cl_cif_args */
4449   cif = &(cl_cif_args->cif);
4450   atypes = (ffi_type **)(((char*)cl_cif_args) + sizeof(closure_and_cif));
4451   for (i=0, p=itypes; i<nargs; i++, p=SCHEME_CDR(p)) {
4452     if (NULL == (base = get_ctype_base(SCHEME_CAR(p)))) {
4453       scheme_thread_code_end_write();
4454       scheme_wrong_contract(who, "(listof ctype?)", ARGPOS(1), argc, argv);
4455     }
4456     if (CTYPE_PRIMLABEL(base) == FOREIGN_void) {
4457       scheme_thread_code_end_write();
4458       wrong_void(who, SCHEME_CAR(p), 1, ARGPOS(1), argc, argv);
4459     }
4460     atypes[i] = CTYPE_ARG_PRIMTYPE(base);
4461   }
4462   if (varargs_after == -1) {
4463     if (ffi_prep_cif(cif, abi, nargs, rtype, atypes) != FFI_OK)
4464       scheme_signal_error("internal error: ffi_prep_cif did not return FFI_OK");
4465   } else {
4466     if (ffi_prep_cif_var(cif, abi, varargs_after, nargs, rtype, atypes) != FFI_OK)
4467       scheme_signal_error("internal error: ffi_prep_cif_var did not return FFI_OK");
4468   }
4469   scheme_thread_code_end_write();
4470   data = (ffi_callback_struct*)scheme_malloc_tagged(sizeof(ffi_callback_struct));
4471   data->so.type = ffi_callback_tag;
4472   data->callback = (cl_cif_args);
4473   data->proc = ((curry ? NULL : argv[ARGPOS(0)]));
4474   data->itypes = (argv[ARGPOS(1)]);
4475   data->otype = (argv[ARGPOS(2)]);
4476   data->sync = (sync);
4477 # ifdef MZ_PRECISE_GC
4478   {
4479     /* put data in immobile, weak box */
4480     GC_CAN_IGNORE void **tmp;
4481     tmp = GC_malloc_immobile_box(GC_malloc_weak_box(data, NULL, 0, 1));
4482     callback_data = (struct immobile_box*)tmp;
4483   }
4484 # else /* MZ_PRECISE_GC undefined */
4485   callback_data = (void*)data;
4486 # endif /* MZ_PRECISE_GC */
4487 # ifdef MZ_USE_MZRT
4488   if (keep_queue) {
4489     /* For ffi_queue_callback(), add a level of indirection in `data' to
4490        hold the place-specific `ffi_sync_queue'.  Use
4491        `free_cl_cif_queue_args' to clean up this extra level. */
4492     GC_CAN_IGNORE void **tmp, *cr;
4493     if (constant_reply) {
4494       cr = malloc(constant_reply_size ? constant_reply_size : 1);
4495       memcpy(cr, constant_reply, constant_reply_size);
4496       constant_reply = cr;
4497     }
4498     tmp = (void **)malloc(sizeof(void*) * 4);
4499     tmp[0] = callback_data;
4500     tmp[1] = ffi_sync_queue;
4501     tmp[2] = constant_reply;
4502     tmp[3] = (void *)(intptr_t)constant_reply_size;
4503     callback_data = (void *)tmp;
4504   }
4505 # endif /* MZ_USE_MZRT */
4506   scheme_thread_code_start_write();
4507   cl_cif_args->data = callback_data;
4508   ffi_ok = ffi_prep_closure_loc(cl, cif, do_callback, (void*)(cl_cif_args->data), cl);
4509   scheme_thread_code_end_write();
4510   if (ffi_ok != FFI_OK)
4511     scheme_signal_error
4512       ("internal error: ffi_prep_closure did not return FFI_OK");
4513 # ifdef MZ_USE_MZRT
4514   if (keep_queue)
4515     scheme_register_finalizer(data, free_cl_cif_queue_args, cl_cif_args,
4516                               NULL, NULL);
4517   else
4518 # endif /* MZ_USE_MZRT */
4519   scheme_register_finalizer(data, free_cl_cif_args, cl_cif_args, NULL, NULL);
4520 
4521   scheme_performance_record_end("comp-ffi-back", &perf_state);
4522 
4523   return (Scheme_Object*)data;
4524 #undef ARGPOS
4525 }
4526 
4527 /* (ffi-callback scheme-proc in-types out-type [abi atomic? sync]) -> ffi-callback */
4528 /* the treatment of in-types and out-types is similar to that in ffi-call */
4529 /* the real work is done by ffi_do_callback above */
4530 #define MYNAME "ffi-callback"
foreign_ffi_callback(int argc,Scheme_Object * argv[])4531 static Scheme_Object *foreign_ffi_callback(int argc, Scheme_Object *argv[])
4532 {
4533   return ffi_callback_or_curry(MYNAME, 0, argc, argv);
4534 }
4535 #undef MYNAME
4536 
make_ffi_callback_from_curried(int argc,Scheme_Object * argv[],Scheme_Object * self)4537 static Scheme_Object *make_ffi_callback_from_curried(int argc, Scheme_Object *argv[], Scheme_Object *self)
4538 {
4539   Scheme_Object *vec = SCHEME_PRIM_CLOSURE_ELS(self)[0];
4540   Scheme_Object *a[7];
4541   int c = SCHEME_VEC_SIZE(vec), i;
4542 
4543   for (i = 0; i < c; i++) {
4544     a[i+1] = SCHEME_VEC_ELS(vec)[i];
4545   }
4546   a[0] = argv[0];
4547 
4548   return ffi_callback_or_curry("make-ffi-callback", 0, c+1, a);
4549 }
4550 
4551 /* (ffi-callback-maker in-types out-type [abi atomic? sync]) -> (proc -> ffi-callback) */
4552 /* Curried version of `ffi-callback`. Check arguments eagerly, but we don't do anything
4553    otherwise until a function is available. */
4554 #define MYNAME "ffi-callback-maker"
foreign_ffi_callback_maker(int argc,Scheme_Object * argv[])4555 static Scheme_Object *foreign_ffi_callback_maker(int argc, Scheme_Object *argv[])
4556 {
4557   int i;
4558   Scheme_Object *vec, *a[1];
4559 
4560   (void)ffi_callback_or_curry(MYNAME, 1, argc, argv);
4561 
4562   vec = scheme_make_vector(argc, NULL);
4563   for (i = 0; i < argc; i++) {
4564     SCHEME_VEC_ELS(vec)[i] = argv[i];
4565   }
4566   a[0] = vec;
4567 
4568   return scheme_make_prim_closure_w_arity(make_ffi_callback_from_curried,
4569                                           1, a,
4570                                           "make-ffi-callback",
4571                                           1, 1);
4572 }
4573 #undef MYNAME
4574 
4575 /*****************************************************************************/
4576 
4577 #ifdef WINDOWS_DYNAMIC_LOAD
4578 typedef int *(*get_errno_ptr_t)(void);
4579 static get_errno_ptr_t get_errno_ptr;
4580 #endif /* WINDOWS_DYNAMIC_LOAD */
4581 
save_errno_values(int kind)4582 static void save_errno_values(int kind)
4583 {
4584   Scheme_Thread *p = scheme_current_thread;
4585 
4586   if (kind == 2) {
4587     intptr_t v = 0;
4588 #   ifdef WINDOWS_DYNAMIC_LOAD
4589     v = GetLastError();
4590 #   endif /* WINDOWS_DYNAMIC_LOAD */
4591     p->saved_errno = v;
4592     return;
4593   }
4594 
4595 # ifdef WINDOWS_DYNAMIC_LOAD
4596   /* Depending on how Racket is compiled and linked, `errno` might
4597      not corresponds to the one from "MSVCRT.dll", which is likely
4598      to be the one that foreign code uses. Go get that one via
4599      _errno(), which returns a pointer to the current thread's
4600      `errno`. */
4601   if (!get_errno_ptr) {
4602     HMODULE hm;
4603     hm = LoadLibrary("msvcrt.dll");
4604     if (hm) {
4605       get_errno_ptr = (get_errno_ptr_t)GetProcAddress(hm, "_errno");
4606     }
4607   }
4608 
4609   if (get_errno_ptr) {
4610     GC_CAN_IGNORE int *errno_ptr;
4611     errno_ptr = get_errno_ptr();
4612     errno = *errno_ptr;
4613   }
4614 # endif /* WINDOWS_DYNAMIC_LOAD */
4615 
4616   p->saved_errno = errno;
4617 }
4618 
4619 #define MYNAME "saved-errno"
foreign_saved_errno(int argc,Scheme_Object * argv[])4620 static Scheme_Object *foreign_saved_errno(int argc, Scheme_Object *argv[])
4621 {
4622   Scheme_Thread *p = scheme_current_thread;
4623   if (argc == 0) {
4624     return scheme_make_integer_value(p->saved_errno);
4625   } else {
4626     intptr_t v;
4627     if (!scheme_get_int_val(argv[0], &v)) {
4628       wrong_intptr(MYNAME, 0, argc, argv);
4629     }
4630     p->saved_errno = v;
4631     return scheme_void;
4632   }
4633 }
4634 #undef MYNAME
4635 
4636 #define MYNAME "lookup-errno"
foreign_lookup_errno(int argc,Scheme_Object * argv[])4637 static Scheme_Object *foreign_lookup_errno(int argc, Scheme_Object *argv[])
4638 {
4639   Scheme_Object *v = argv[0];
4640   if (!SCHEME_SYMBOLP(v)) {
4641     scheme_wrong_contract(MYNAME, "symbol?", 0, argc, argv);
4642     return NULL;
4643   }
4644   if (SCHEME_SYM_WEIRDP(v))
4645     return scheme_false;
4646 # ifdef E2BIG
4647   if (!strcmp("E2BIG", SCHEME_SYM_VAL(v)))
4648     return scheme_make_integer(E2BIG);
4649 # endif /* E2BIG */
4650 # ifdef EACCES
4651   if (!strcmp("EACCES", SCHEME_SYM_VAL(v)))
4652     return scheme_make_integer(EACCES);
4653 # endif /* EACCES */
4654 # ifdef EADDRINUSE
4655   if (!strcmp("EADDRINUSE", SCHEME_SYM_VAL(v)))
4656     return scheme_make_integer(EADDRINUSE);
4657 # endif /* EADDRINUSE */
4658 # ifdef EADDRNOTAVAIL
4659   if (!strcmp("EADDRNOTAVAIL", SCHEME_SYM_VAL(v)))
4660     return scheme_make_integer(EADDRNOTAVAIL);
4661 # endif /* EADDRNOTAVAIL */
4662 # ifdef EAFNOSUPPORT
4663   if (!strcmp("EAFNOSUPPORT", SCHEME_SYM_VAL(v)))
4664     return scheme_make_integer(EAFNOSUPPORT);
4665 # endif /* EAFNOSUPPORT */
4666 # ifdef EAGAIN
4667   if (!strcmp("EAGAIN", SCHEME_SYM_VAL(v)))
4668     return scheme_make_integer(EAGAIN);
4669 # endif /* EAGAIN */
4670 # ifdef EALREADY
4671   if (!strcmp("EALREADY", SCHEME_SYM_VAL(v)))
4672     return scheme_make_integer(EALREADY);
4673 # endif /* EALREADY */
4674 # ifdef EBADF
4675   if (!strcmp("EBADF", SCHEME_SYM_VAL(v)))
4676     return scheme_make_integer(EBADF);
4677 # endif /* EBADF */
4678 # ifdef EBADMSG
4679   if (!strcmp("EBADMSG", SCHEME_SYM_VAL(v)))
4680     return scheme_make_integer(EBADMSG);
4681 # endif /* EBADMSG */
4682 # ifdef EBUSY
4683   if (!strcmp("EBUSY", SCHEME_SYM_VAL(v)))
4684     return scheme_make_integer(EBUSY);
4685 # endif /* EBUSY */
4686 # ifdef ECANCELED
4687   if (!strcmp("ECANCELED", SCHEME_SYM_VAL(v)))
4688     return scheme_make_integer(ECANCELED);
4689 # endif /* ECANCELED */
4690 # ifdef ECHILD
4691   if (!strcmp("ECHILD", SCHEME_SYM_VAL(v)))
4692     return scheme_make_integer(ECHILD);
4693 # endif /* ECHILD */
4694 # ifdef ECONNABORTED
4695   if (!strcmp("ECONNABORTED", SCHEME_SYM_VAL(v)))
4696     return scheme_make_integer(ECONNABORTED);
4697 # endif /* ECONNABORTED */
4698 # ifdef ECONNREFUSED
4699   if (!strcmp("ECONNREFUSED", SCHEME_SYM_VAL(v)))
4700     return scheme_make_integer(ECONNREFUSED);
4701 # endif /* ECONNREFUSED */
4702 # ifdef ECONNRESET
4703   if (!strcmp("ECONNRESET", SCHEME_SYM_VAL(v)))
4704     return scheme_make_integer(ECONNRESET);
4705 # endif /* ECONNRESET */
4706 # ifdef EDEADLK
4707   if (!strcmp("EDEADLK", SCHEME_SYM_VAL(v)))
4708     return scheme_make_integer(EDEADLK);
4709 # endif /* EDEADLK */
4710 # ifdef EDESTADDRREQ
4711   if (!strcmp("EDESTADDRREQ", SCHEME_SYM_VAL(v)))
4712     return scheme_make_integer(EDESTADDRREQ);
4713 # endif /* EDESTADDRREQ */
4714 # ifdef EDOM
4715   if (!strcmp("EDOM", SCHEME_SYM_VAL(v)))
4716     return scheme_make_integer(EDOM);
4717 # endif /* EDOM */
4718 # ifdef EDQUOT
4719   if (!strcmp("EDQUOT", SCHEME_SYM_VAL(v)))
4720     return scheme_make_integer(EDQUOT);
4721 # endif /* EDQUOT */
4722 # ifdef EEXIST
4723   if (!strcmp("EEXIST", SCHEME_SYM_VAL(v)))
4724     return scheme_make_integer(EEXIST);
4725 # endif /* EEXIST */
4726 # ifdef EFAULT
4727   if (!strcmp("EFAULT", SCHEME_SYM_VAL(v)))
4728     return scheme_make_integer(EFAULT);
4729 # endif /* EFAULT */
4730 # ifdef EFBIG
4731   if (!strcmp("EFBIG", SCHEME_SYM_VAL(v)))
4732     return scheme_make_integer(EFBIG);
4733 # endif /* EFBIG */
4734 # ifdef EHOSTUNREACH
4735   if (!strcmp("EHOSTUNREACH", SCHEME_SYM_VAL(v)))
4736     return scheme_make_integer(EHOSTUNREACH);
4737 # endif /* EHOSTUNREACH */
4738 # ifdef EIDRM
4739   if (!strcmp("EIDRM", SCHEME_SYM_VAL(v)))
4740     return scheme_make_integer(EIDRM);
4741 # endif /* EIDRM */
4742 # ifdef EILSEQ
4743   if (!strcmp("EILSEQ", SCHEME_SYM_VAL(v)))
4744     return scheme_make_integer(EILSEQ);
4745 # endif /* EILSEQ */
4746 # ifdef EINPROGRESS
4747   if (!strcmp("EINPROGRESS", SCHEME_SYM_VAL(v)))
4748     return scheme_make_integer(EINPROGRESS);
4749 # endif /* EINPROGRESS */
4750 # ifdef EINTR
4751   if (!strcmp("EINTR", SCHEME_SYM_VAL(v)))
4752     return scheme_make_integer(EINTR);
4753 # endif /* EINTR */
4754 # ifdef EINVAL
4755   if (!strcmp("EINVAL", SCHEME_SYM_VAL(v)))
4756     return scheme_make_integer(EINVAL);
4757 # endif /* EINVAL */
4758 # ifdef EIO
4759   if (!strcmp("EIO", SCHEME_SYM_VAL(v)))
4760     return scheme_make_integer(EIO);
4761 # endif /* EIO */
4762 # ifdef EISCONN
4763   if (!strcmp("EISCONN", SCHEME_SYM_VAL(v)))
4764     return scheme_make_integer(EISCONN);
4765 # endif /* EISCONN */
4766 # ifdef EISDIR
4767   if (!strcmp("EISDIR", SCHEME_SYM_VAL(v)))
4768     return scheme_make_integer(EISDIR);
4769 # endif /* EISDIR */
4770 # ifdef ELOOP
4771   if (!strcmp("ELOOP", SCHEME_SYM_VAL(v)))
4772     return scheme_make_integer(ELOOP);
4773 # endif /* ELOOP */
4774 # ifdef EMFILE
4775   if (!strcmp("EMFILE", SCHEME_SYM_VAL(v)))
4776     return scheme_make_integer(EMFILE);
4777 # endif /* EMFILE */
4778 # ifdef EMLINK
4779   if (!strcmp("EMLINK", SCHEME_SYM_VAL(v)))
4780     return scheme_make_integer(EMLINK);
4781 # endif /* EMLINK */
4782 # ifdef EMSGSIZE
4783   if (!strcmp("EMSGSIZE", SCHEME_SYM_VAL(v)))
4784     return scheme_make_integer(EMSGSIZE);
4785 # endif /* EMSGSIZE */
4786 # ifdef EMULTIHOP
4787   if (!strcmp("EMULTIHOP", SCHEME_SYM_VAL(v)))
4788     return scheme_make_integer(EMULTIHOP);
4789 # endif /* EMULTIHOP */
4790 # ifdef ENAMETOOLONG
4791   if (!strcmp("ENAMETOOLONG", SCHEME_SYM_VAL(v)))
4792     return scheme_make_integer(ENAMETOOLONG);
4793 # endif /* ENAMETOOLONG */
4794 # ifdef ENETDOWN
4795   if (!strcmp("ENETDOWN", SCHEME_SYM_VAL(v)))
4796     return scheme_make_integer(ENETDOWN);
4797 # endif /* ENETDOWN */
4798 # ifdef ENETRESET
4799   if (!strcmp("ENETRESET", SCHEME_SYM_VAL(v)))
4800     return scheme_make_integer(ENETRESET);
4801 # endif /* ENETRESET */
4802 # ifdef ENETUNREACH
4803   if (!strcmp("ENETUNREACH", SCHEME_SYM_VAL(v)))
4804     return scheme_make_integer(ENETUNREACH);
4805 # endif /* ENETUNREACH */
4806 # ifdef ENFILE
4807   if (!strcmp("ENFILE", SCHEME_SYM_VAL(v)))
4808     return scheme_make_integer(ENFILE);
4809 # endif /* ENFILE */
4810 # ifdef ENOBUFS
4811   if (!strcmp("ENOBUFS", SCHEME_SYM_VAL(v)))
4812     return scheme_make_integer(ENOBUFS);
4813 # endif /* ENOBUFS */
4814 # ifdef ENODATA
4815   if (!strcmp("ENODATA", SCHEME_SYM_VAL(v)))
4816     return scheme_make_integer(ENODATA);
4817 # endif /* ENODATA */
4818 # ifdef ENODEV
4819   if (!strcmp("ENODEV", SCHEME_SYM_VAL(v)))
4820     return scheme_make_integer(ENODEV);
4821 # endif /* ENODEV */
4822 # ifdef ENOENT
4823   if (!strcmp("ENOENT", SCHEME_SYM_VAL(v)))
4824     return scheme_make_integer(ENOENT);
4825 # endif /* ENOENT */
4826 # ifdef ENOEXEC
4827   if (!strcmp("ENOEXEC", SCHEME_SYM_VAL(v)))
4828     return scheme_make_integer(ENOEXEC);
4829 # endif /* ENOEXEC */
4830 # ifdef ENOLCK
4831   if (!strcmp("ENOLCK", SCHEME_SYM_VAL(v)))
4832     return scheme_make_integer(ENOLCK);
4833 # endif /* ENOLCK */
4834 # ifdef ENOLINK
4835   if (!strcmp("ENOLINK", SCHEME_SYM_VAL(v)))
4836     return scheme_make_integer(ENOLINK);
4837 # endif /* ENOLINK */
4838 # ifdef ENOMEM
4839   if (!strcmp("ENOMEM", SCHEME_SYM_VAL(v)))
4840     return scheme_make_integer(ENOMEM);
4841 # endif /* ENOMEM */
4842 # ifdef ENOMSG
4843   if (!strcmp("ENOMSG", SCHEME_SYM_VAL(v)))
4844     return scheme_make_integer(ENOMSG);
4845 # endif /* ENOMSG */
4846 # ifdef ENOPROTOOPT
4847   if (!strcmp("ENOPROTOOPT", SCHEME_SYM_VAL(v)))
4848     return scheme_make_integer(ENOPROTOOPT);
4849 # endif /* ENOPROTOOPT */
4850 # ifdef ENOSPC
4851   if (!strcmp("ENOSPC", SCHEME_SYM_VAL(v)))
4852     return scheme_make_integer(ENOSPC);
4853 # endif /* ENOSPC */
4854 # ifdef ENOSR
4855   if (!strcmp("ENOSR", SCHEME_SYM_VAL(v)))
4856     return scheme_make_integer(ENOSR);
4857 # endif /* ENOSR */
4858 # ifdef ENOSTR
4859   if (!strcmp("ENOSTR", SCHEME_SYM_VAL(v)))
4860     return scheme_make_integer(ENOSTR);
4861 # endif /* ENOSTR */
4862 # ifdef ENOSYS
4863   if (!strcmp("ENOSYS", SCHEME_SYM_VAL(v)))
4864     return scheme_make_integer(ENOSYS);
4865 # endif /* ENOSYS */
4866 # ifdef ENOTCONN
4867   if (!strcmp("ENOTCONN", SCHEME_SYM_VAL(v)))
4868     return scheme_make_integer(ENOTCONN);
4869 # endif /* ENOTCONN */
4870 # ifdef ENOTDIR
4871   if (!strcmp("ENOTDIR", SCHEME_SYM_VAL(v)))
4872     return scheme_make_integer(ENOTDIR);
4873 # endif /* ENOTDIR */
4874 # ifdef ENOTEMPTY
4875   if (!strcmp("ENOTEMPTY", SCHEME_SYM_VAL(v)))
4876     return scheme_make_integer(ENOTEMPTY);
4877 # endif /* ENOTEMPTY */
4878 # ifdef ENOTRECOVERABLE
4879   if (!strcmp("ENOTRECOVERABLE", SCHEME_SYM_VAL(v)))
4880     return scheme_make_integer(ENOTRECOVERABLE);
4881 # endif /* ENOTRECOVERABLE */
4882 # ifdef ENOTSOCK
4883   if (!strcmp("ENOTSOCK", SCHEME_SYM_VAL(v)))
4884     return scheme_make_integer(ENOTSOCK);
4885 # endif /* ENOTSOCK */
4886 # ifdef ENOTSUP
4887   if (!strcmp("ENOTSUP", SCHEME_SYM_VAL(v)))
4888     return scheme_make_integer(ENOTSUP);
4889 # endif /* ENOTSUP */
4890 # ifdef ENOTTY
4891   if (!strcmp("ENOTTY", SCHEME_SYM_VAL(v)))
4892     return scheme_make_integer(ENOTTY);
4893 # endif /* ENOTTY */
4894 # ifdef ENXIO
4895   if (!strcmp("ENXIO", SCHEME_SYM_VAL(v)))
4896     return scheme_make_integer(ENXIO);
4897 # endif /* ENXIO */
4898 # ifdef EOPNOTSUPP
4899   if (!strcmp("EOPNOTSUPP", SCHEME_SYM_VAL(v)))
4900     return scheme_make_integer(EOPNOTSUPP);
4901 # endif /* EOPNOTSUPP */
4902 # ifdef EOVERFLOW
4903   if (!strcmp("EOVERFLOW", SCHEME_SYM_VAL(v)))
4904     return scheme_make_integer(EOVERFLOW);
4905 # endif /* EOVERFLOW */
4906 # ifdef EOWNERDEAD
4907   if (!strcmp("EOWNERDEAD", SCHEME_SYM_VAL(v)))
4908     return scheme_make_integer(EOWNERDEAD);
4909 # endif /* EOWNERDEAD */
4910 # ifdef EPERM
4911   if (!strcmp("EPERM", SCHEME_SYM_VAL(v)))
4912     return scheme_make_integer(EPERM);
4913 # endif /* EPERM */
4914 # ifdef EPIPE
4915   if (!strcmp("EPIPE", SCHEME_SYM_VAL(v)))
4916     return scheme_make_integer(EPIPE);
4917 # endif /* EPIPE */
4918 # ifdef EPROTO
4919   if (!strcmp("EPROTO", SCHEME_SYM_VAL(v)))
4920     return scheme_make_integer(EPROTO);
4921 # endif /* EPROTO */
4922 # ifdef EPROTONOSUPPORT
4923   if (!strcmp("EPROTONOSUPPORT", SCHEME_SYM_VAL(v)))
4924     return scheme_make_integer(EPROTONOSUPPORT);
4925 # endif /* EPROTONOSUPPORT */
4926 # ifdef EPROTOTYPE
4927   if (!strcmp("EPROTOTYPE", SCHEME_SYM_VAL(v)))
4928     return scheme_make_integer(EPROTOTYPE);
4929 # endif /* EPROTOTYPE */
4930 # ifdef ERANGE
4931   if (!strcmp("ERANGE", SCHEME_SYM_VAL(v)))
4932     return scheme_make_integer(ERANGE);
4933 # endif /* ERANGE */
4934 # ifdef EROFS
4935   if (!strcmp("EROFS", SCHEME_SYM_VAL(v)))
4936     return scheme_make_integer(EROFS);
4937 # endif /* EROFS */
4938 # ifdef ESPIPE
4939   if (!strcmp("ESPIPE", SCHEME_SYM_VAL(v)))
4940     return scheme_make_integer(ESPIPE);
4941 # endif /* ESPIPE */
4942 # ifdef ESRCH
4943   if (!strcmp("ESRCH", SCHEME_SYM_VAL(v)))
4944     return scheme_make_integer(ESRCH);
4945 # endif /* ESRCH */
4946 # ifdef ESTALE
4947   if (!strcmp("ESTALE", SCHEME_SYM_VAL(v)))
4948     return scheme_make_integer(ESTALE);
4949 # endif /* ESTALE */
4950 # ifdef ETIME
4951   if (!strcmp("ETIME", SCHEME_SYM_VAL(v)))
4952     return scheme_make_integer(ETIME);
4953 # endif /* ETIME */
4954 # ifdef ETIMEDOUT
4955   if (!strcmp("ETIMEDOUT", SCHEME_SYM_VAL(v)))
4956     return scheme_make_integer(ETIMEDOUT);
4957 # endif /* ETIMEDOUT */
4958 # ifdef ETXTBSY
4959   if (!strcmp("ETXTBSY", SCHEME_SYM_VAL(v)))
4960     return scheme_make_integer(ETXTBSY);
4961 # endif /* ETXTBSY */
4962 # ifdef EWOULDBLOCK
4963   if (!strcmp("EWOULDBLOCK", SCHEME_SYM_VAL(v)))
4964     return scheme_make_integer(EWOULDBLOCK);
4965 # endif /* EWOULDBLOCK */
4966 # ifdef EXDEV
4967   if (!strcmp("EXDEV", SCHEME_SYM_VAL(v)))
4968     return scheme_make_integer(EXDEV);
4969 # endif /* EXDEV */
4970   return scheme_false;
4971 }
4972 #undef MYNAME
4973 
4974 /*****************************************************************************/
4975 
4976 /* (make-late-will-executor) -> #<will-executor> */
4977 #define MYNAME "make-late-will-executor"
foreign_make_late_will_executor(int argc,Scheme_Object * argv[])4978 static Scheme_Object *foreign_make_late_will_executor(int argc, Scheme_Object *argv[])
4979 {
4980   return scheme_make_late_will_executor();
4981 }
4982 #undef MYNAME
4983 
4984 /* (make-late-weak-box val) -> #<weak-box> */
4985 #define MYNAME "make-late-weak-box"
foreign_make_late_weak_box(int argc,Scheme_Object * argv[])4986 static Scheme_Object *foreign_make_late_weak_box(int argc, Scheme_Object *argv[])
4987 {
4988   return scheme_make_late_weak_box(argv[0]);
4989 }
4990 #undef MYNAME
4991 
4992 /* (make-late-weak-hasheq) -> #<hash> */
4993 #define MYNAME "make-late-weak-hasheq"
foreign_make_late_weak_hasheq(int argc,Scheme_Object * argv[])4994 static Scheme_Object *foreign_make_late_weak_hasheq(int argc, Scheme_Object *argv[])
4995 {
4996   return (Scheme_Object *)scheme_make_bucket_table(20, SCHEME_hash_late_weak_ptr);
4997 }
4998 #undef MYNAME
4999 
5000 /*****************************************************************************/
5001 
ctype_printer(Scheme_Object * ctype,int dis,Scheme_Print_Params * pp)5002 void ctype_printer(Scheme_Object *ctype, int dis, Scheme_Print_Params *pp)
5003 {
5004   char *str;
5005   if (CTYPE_PRIMP(ctype)) {
5006     scheme_print_bytes(pp, "#<ctype:", 0, 8);
5007     ctype = CTYPE_BASETYPE(ctype);
5008     if (SCHEME_SYMBOLP(ctype)) {
5009       str = SCHEME_SYM_VAL(ctype);
5010       scheme_print_bytes(pp, str, 0, strlen(str));
5011     } else {
5012       scheme_print_bytes(pp, "cstruct", 0, 7);
5013     }
5014     scheme_print_bytes(pp, ">", 0, 1);
5015   } else {
5016     scheme_print_bytes(pp, "#<ctype>", 0, 8);
5017   }
5018 }
5019 
5020 /*****************************************************************************/
5021 /* Initialization */
5022 
5023 /* types need to be initialized before places can spawn
5024  * types become entries in the GC mark and fixup tables
5025  * this function should initialize read-only globals that can be
5026  * shared without locking */
scheme_init_foreign_globals()5027 void scheme_init_foreign_globals()
5028 {
5029   ffi_lib_tag = scheme_make_type("<ffi-lib>");
5030   ffi_obj_tag = scheme_make_type("<ffi-obj>");
5031   ;
5032   ffi_callback_tag = scheme_make_type("<ffi-callback>");
5033 # ifdef MZ_PRECISE_GC
5034   GC_register_traversers(ffi_lib_tag, ffi_lib_SIZE, ffi_lib_MARK, ffi_lib_FIXUP, 1, 0);
5035   GC_register_traversers(ffi_obj_tag, ffi_obj_SIZE, ffi_obj_MARK, ffi_obj_FIXUP, 1, 0);
5036   GC_register_traversers(ctype_tag, ctype_SIZE, ctype_MARK, ctype_FIXUP, 1, 0);
5037   GC_register_traversers(ffi_callback_tag, ffi_callback_SIZE, ffi_callback_MARK, ffi_callback_FIXUP, 1, 0);
5038 # endif /* MZ_PRECISE_GC */
5039   scheme_set_type_printer(scheme_ctype_type, ctype_printer);
5040   MZ_REGISTER_STATIC(nonatomic_sym);
5041   nonatomic_sym = scheme_intern_symbol("nonatomic");
5042   MZ_REGISTER_STATIC(atomic_sym);
5043   atomic_sym = scheme_intern_symbol("atomic");
5044   MZ_REGISTER_STATIC(stubborn_sym);
5045   stubborn_sym = scheme_intern_symbol("stubborn");
5046   MZ_REGISTER_STATIC(uncollectable_sym);
5047   uncollectable_sym = scheme_intern_symbol("uncollectable");
5048   MZ_REGISTER_STATIC(eternal_sym);
5049   eternal_sym = scheme_intern_symbol("eternal");
5050   MZ_REGISTER_STATIC(interior_sym);
5051   interior_sym = scheme_intern_symbol("interior");
5052   MZ_REGISTER_STATIC(atomic_interior_sym);
5053   atomic_interior_sym = scheme_intern_symbol("atomic-interior");
5054   MZ_REGISTER_STATIC(raw_sym);
5055   raw_sym = scheme_intern_symbol("raw");
5056   MZ_REGISTER_STATIC(tagged_sym);
5057   tagged_sym = scheme_intern_symbol("tagged");
5058   MZ_REGISTER_STATIC(fail_ok_sym);
5059   fail_ok_sym = scheme_intern_symbol("fail-ok");
5060   MZ_REGISTER_STATIC(default_sym);
5061   default_sym = scheme_intern_symbol("default");
5062   MZ_REGISTER_STATIC(stdcall_sym);
5063   stdcall_sym = scheme_intern_symbol("stdcall");
5064   MZ_REGISTER_STATIC(sysv_sym);
5065   sysv_sym = scheme_intern_symbol("sysv");
5066   MZ_REGISTER_STATIC(abs_sym);
5067   abs_sym = scheme_intern_symbol("abs");
5068 
5069   MZ_REGISTER_STATIC(ffi_name);
5070   ffi_name = scheme_make_byte_string("ffi:proc");
5071 }
5072 
scheme_init_foreign_places()5073 void scheme_init_foreign_places() {
5074   MZ_REGISTER_STATIC(opened_libs);
5075   opened_libs = scheme_make_hash_table(SCHEME_hash_string);
5076 #ifdef MZ_USE_PLACES
5077   if (!orig_place_mutex) {
5078     mzrt_mutex_create(&orig_place_mutex);
5079     orig_place_signal_handle = scheme_get_signal_handle();
5080   }
5081 #endif
5082 }
5083 
scheme_make_inline_noncm_prim(Scheme_Prim * prim,const char * name,mzshort mina,mzshort maxa)5084 static Scheme_Object *scheme_make_inline_noncm_prim(Scheme_Prim *prim,
5085                                                     const char *name,
5086                                                     mzshort mina, mzshort maxa)
5087 {
5088   Scheme_Object *p;
5089   int flags = 0;
5090 
5091   p = scheme_make_noncm_prim(prim, name, mina, maxa);
5092 
5093   if ((mina <= 1) && (maxa >= 1))
5094    flags |= SCHEME_PRIM_IS_UNARY_INLINED;
5095   if ((mina <= 2) && (maxa >= 2))
5096    flags |= SCHEME_PRIM_IS_BINARY_INLINED;
5097   if ((mina <= 0) || (maxa > 2))
5098    flags |= SCHEME_PRIM_IS_NARY_INLINED;
5099 
5100   SCHEME_PRIM_PROC_FLAGS(p) |= scheme_intern_prim_opt_flags(flags);
5101 
5102   return p;
5103 }
5104 
5105 Scheme_Object *scheme_pointer_ctype;
5106 Scheme_Object *scheme_float_ctype;
5107 Scheme_Object *scheme_double_ctype;
5108 Scheme_Object *scheme_int8_ctype;
5109 Scheme_Object *scheme_uint8_ctype;
5110 Scheme_Object *scheme_int16_ctype;
5111 Scheme_Object *scheme_uint16_ctype;
5112 Scheme_Object *scheme_int32_ctype;
5113 Scheme_Object *scheme_uint32_ctype;
5114 Scheme_Object *scheme_int64_ctype;
5115 Scheme_Object *scheme_uint64_ctype;
5116 
scheme_init_foreign(Scheme_Startup_Env * env)5117 void scheme_init_foreign(Scheme_Startup_Env *env)
5118 {
5119   ctype_struct *t;
5120   Scheme_Object *s;
5121   memcpy(&ffi_type_gcpointer, &ffi_type_pointer, sizeof(ffi_type_pointer));
5122   scheme_switch_prim_instance(env, "#%foreign");
5123   scheme_addto_prim_instance("ffi-lib?",
5124     scheme_make_immed_prim(foreign_ffi_lib_p, "ffi-lib?", 1, 1), env);
5125   scheme_addto_prim_instance("ffi-lib",
5126     scheme_make_noncm_prim(foreign_ffi_lib, "ffi-lib", 1, 3), env);
5127   scheme_addto_prim_instance("ffi-lib-name",
5128     scheme_make_noncm_prim(foreign_ffi_lib_name, "ffi-lib-name", 1, 1), env);
5129   scheme_addto_prim_instance("ffi-lib-unload",
5130     scheme_make_noncm_prim(foreign_ffi_lib_unload, "ffi-lib-unload", 1, 1), env);
5131   scheme_addto_prim_instance("ffi-obj?",
5132     scheme_make_immed_prim(foreign_ffi_obj_p, "ffi-obj?", 1, 1), env);
5133   scheme_addto_prim_instance("ffi-obj",
5134     scheme_make_noncm_prim(foreign_ffi_obj, "ffi-obj", 2, 2), env);
5135   scheme_addto_prim_instance("ffi-obj-lib",
5136     scheme_make_immed_prim(foreign_ffi_obj_lib, "ffi-obj-lib", 1, 1), env);
5137   scheme_addto_prim_instance("ffi-obj-name",
5138     scheme_make_immed_prim(foreign_ffi_obj_name, "ffi-obj-name", 1, 1), env);
5139   scheme_addto_prim_instance("ctype?",
5140     scheme_make_immed_prim(foreign_ctype_p, "ctype?", 1, 1), env);
5141   scheme_addto_prim_instance("ctype-basetype",
5142     scheme_make_immed_prim(foreign_ctype_basetype, "ctype-basetype", 1, 1), env);
5143   scheme_addto_prim_instance("ctype-scheme->c",
5144     scheme_make_immed_prim(foreign_ctype_scheme_to_c, "ctype-scheme->c", 1, 1), env);
5145   scheme_addto_prim_instance("ctype-c->scheme",
5146     scheme_make_immed_prim(foreign_ctype_c_to_scheme, "ctype-c->scheme", 1, 1), env);
5147   scheme_addto_prim_instance("make-ctype",
5148     scheme_make_noncm_prim(foreign_make_ctype, "make-ctype", 3, 3), env);
5149   scheme_addto_prim_instance("make-cstruct-type",
5150     scheme_make_noncm_prim(foreign_make_cstruct_type, "make-cstruct-type", 1, 4), env);
5151   scheme_addto_prim_instance("make-array-type",
5152     scheme_make_noncm_prim(foreign_make_array_type, "make-array-type", 2, 2), env);
5153   scheme_addto_prim_instance("make-union-type",
5154     scheme_make_noncm_prim(foreign_make_union_type, "make-union-type", 1, -1), env);
5155   scheme_addto_prim_instance("ffi-callback?",
5156     scheme_make_immed_prim(foreign_ffi_callback_p, "ffi-callback?", 1, 1), env);
5157   scheme_addto_prim_instance("cpointer?",
5158     scheme_make_immed_prim(foreign_cpointer_p, "cpointer?", 1, 1), env);
5159   scheme_addto_prim_instance("cpointer-tag",
5160     scheme_make_inline_noncm_prim(foreign_cpointer_tag, "cpointer-tag", 1, 1), env);
5161   scheme_addto_prim_instance("set-cpointer-tag!",
5162     scheme_make_inline_noncm_prim(foreign_set_cpointer_tag_bang, "set-cpointer-tag!", 2, 2), env);
5163   scheme_addto_prim_instance("cpointer-gcable?",
5164     scheme_make_noncm_prim(foreign_cpointer_gcable_p, "cpointer-gcable?", 1, 1), env);
5165   scheme_addto_prim_instance("ctype-sizeof",
5166     scheme_make_immed_prim(foreign_ctype_sizeof, "ctype-sizeof", 1, 1), env);
5167   scheme_addto_prim_instance("ctype-alignof",
5168     scheme_make_immed_prim(foreign_ctype_alignof, "ctype-alignof", 1, 1), env);
5169   scheme_addto_prim_instance("compiler-sizeof",
5170     scheme_make_immed_prim(foreign_compiler_sizeof, "compiler-sizeof", 1, 1), env);
5171   scheme_addto_prim_instance("malloc",
5172     scheme_make_noncm_prim(foreign_malloc, "malloc", 1, 5), env);
5173   scheme_addto_prim_instance("end-stubborn-change",
5174     scheme_make_noncm_prim(foreign_end_stubborn_change, "end-stubborn-change", 1, 1), env);
5175   scheme_addto_prim_instance("free",
5176     scheme_make_noncm_prim(foreign_free, "free", 1, 1), env);
5177   scheme_addto_prim_instance("malloc-immobile-cell",
5178     scheme_make_immed_prim(foreign_malloc_immobile_cell, "malloc-immobile-cell", 1, 1), env);
5179   scheme_addto_prim_instance("free-immobile-cell",
5180     scheme_make_noncm_prim(foreign_free_immobile_cell, "free-immobile-cell", 1, 1), env);
5181   scheme_addto_prim_instance("ptr-add",
5182     scheme_make_noncm_prim(foreign_ptr_add, "ptr-add", 2, 3), env);
5183   scheme_addto_prim_instance("ptr-add!",
5184     scheme_make_noncm_prim(foreign_ptr_add_bang, "ptr-add!", 2, 3), env);
5185   scheme_addto_prim_instance("offset-ptr?",
5186     scheme_make_noncm_prim(foreign_offset_ptr_p, "offset-ptr?", 1, 1), env);
5187   scheme_addto_prim_instance("ptr-offset",
5188     scheme_make_noncm_prim(foreign_ptr_offset, "ptr-offset", 1, 1), env);
5189   scheme_addto_prim_instance("set-ptr-offset!",
5190     scheme_make_noncm_prim(foreign_set_ptr_offset_bang, "set-ptr-offset!", 2, 3), env);
5191   scheme_addto_prim_instance("vector->cpointer",
5192     scheme_make_immed_prim(foreign_vector_to_cpointer, "vector->cpointer", 1, 1), env);
5193   scheme_addto_prim_instance("flvector->cpointer",
5194     scheme_make_immed_prim(foreign_flvector_to_cpointer, "flvector->cpointer", 1, 1), env);
5195   scheme_addto_prim_instance("extflvector->cpointer",
5196     scheme_make_immed_prim(foreign_extflvector_to_cpointer, "extflvector->cpointer", 1, 1), env);
5197   scheme_addto_prim_instance("memset",
5198     scheme_make_noncm_prim(foreign_memset, "memset", 3, 5), env);
5199   scheme_addto_prim_instance("memmove",
5200     scheme_make_noncm_prim(foreign_memmove, "memmove", 3, 6), env);
5201   scheme_addto_prim_instance("memcpy",
5202     scheme_make_noncm_prim(foreign_memcpy, "memcpy", 3, 6), env);
5203   scheme_addto_prim_instance("ptr-ref",
5204     scheme_make_inline_noncm_prim(foreign_ptr_ref, "ptr-ref", 2, 4), env);
5205   scheme_addto_prim_instance("ptr-set!",
5206     scheme_make_inline_noncm_prim(foreign_ptr_set_bang, "ptr-set!", 3, 5), env);
5207   scheme_addto_prim_instance("ptr-equal?",
5208     scheme_make_noncm_prim(foreign_ptr_equal_p, "ptr-equal?", 2, 2), env);
5209   scheme_addto_prim_instance("make-sized-byte-string",
5210     scheme_make_noncm_prim(foreign_make_sized_byte_string, "make-sized-byte-string", 2, 2), env);
5211   scheme_addto_prim_instance("ffi-call",
5212     scheme_make_noncm_prim(foreign_ffi_call, "ffi-call", 3, 10), env);
5213   scheme_addto_prim_instance("ffi-call-maker",
5214     scheme_make_noncm_prim(foreign_ffi_call_maker, "ffi-call-maker", 2, 9), env);
5215   scheme_addto_prim_instance("ffi-callback",
5216     scheme_make_noncm_prim(foreign_ffi_callback, "ffi-callback", 3, 6), env);
5217   scheme_addto_prim_instance("ffi-callback-maker",
5218     scheme_make_noncm_prim(foreign_ffi_callback_maker, "ffi-callback-maker", 2, 6), env);
5219   scheme_addto_prim_instance("saved-errno",
5220     scheme_make_immed_prim(foreign_saved_errno, "saved-errno", 0, 1), env);
5221   scheme_addto_prim_instance("lookup-errno",
5222     scheme_make_immed_prim(foreign_lookup_errno, "lookup-errno", 1, 1), env);
5223   scheme_addto_prim_instance("make-late-will-executor",
5224     scheme_make_immed_prim(foreign_make_late_will_executor, "make-late-will-executor", 0, 0), env);
5225   scheme_addto_prim_instance("make-late-weak-box",
5226     scheme_make_immed_prim(foreign_make_late_weak_box, "make-late-weak-box", 1, 1), env);
5227   scheme_addto_prim_instance("make-late-weak-hasheq",
5228     scheme_make_immed_prim(foreign_make_late_weak_hasheq, "make-late-weak-hasheq", 0, 0), env);
5229   s = scheme_intern_symbol("void");
5230   t = (ctype_struct*)scheme_malloc_tagged(sizeof(ctype_struct));
5231   t->so.type = ctype_tag;
5232   t->basetype = (s);
5233   t->scheme_to_c = ((Scheme_Object*)(void*)(&ffi_type_void));
5234   t->c_to_scheme = ((Scheme_Object*)FOREIGN_void);
5235   scheme_addto_prim_instance("_void", (Scheme_Object*)t, env);
5236   s = scheme_intern_symbol("int8");
5237   t = (ctype_struct*)scheme_malloc_tagged(sizeof(ctype_struct));
5238   t->so.type = ctype_tag;
5239   t->basetype = (s);
5240   t->scheme_to_c = ((Scheme_Object*)(void*)(&ffi_type_sint8));
5241   t->c_to_scheme = ((Scheme_Object*)FOREIGN_int8);
5242   REGISTER_SO(scheme_int8_ctype);
5243   scheme_int8_ctype = (Scheme_Object *)t;
5244   scheme_addto_prim_instance("_int8", (Scheme_Object*)t, env);
5245   s = scheme_intern_symbol("uint8");
5246   t = (ctype_struct*)scheme_malloc_tagged(sizeof(ctype_struct));
5247   t->so.type = ctype_tag;
5248   t->basetype = (s);
5249   t->scheme_to_c = ((Scheme_Object*)(void*)(&ffi_type_uint8));
5250   t->c_to_scheme = ((Scheme_Object*)FOREIGN_uint8);
5251   REGISTER_SO(scheme_uint8_ctype);
5252   scheme_uint8_ctype = (Scheme_Object *)t;
5253   scheme_addto_prim_instance("_uint8", (Scheme_Object*)t, env);
5254   s = scheme_intern_symbol("int16");
5255   t = (ctype_struct*)scheme_malloc_tagged(sizeof(ctype_struct));
5256   t->so.type = ctype_tag;
5257   t->basetype = (s);
5258   t->scheme_to_c = ((Scheme_Object*)(void*)(&ffi_type_sint16));
5259   t->c_to_scheme = ((Scheme_Object*)FOREIGN_int16);
5260   REGISTER_SO(scheme_int16_ctype);
5261   scheme_int16_ctype = (Scheme_Object *)t;
5262   scheme_addto_prim_instance("_int16", (Scheme_Object*)t, env);
5263   s = scheme_intern_symbol("uint16");
5264   t = (ctype_struct*)scheme_malloc_tagged(sizeof(ctype_struct));
5265   t->so.type = ctype_tag;
5266   t->basetype = (s);
5267   t->scheme_to_c = ((Scheme_Object*)(void*)(&ffi_type_uint16));
5268   t->c_to_scheme = ((Scheme_Object*)FOREIGN_uint16);
5269   REGISTER_SO(scheme_uint16_ctype);
5270   scheme_uint16_ctype = (Scheme_Object *)t;
5271   scheme_addto_prim_instance("_uint16", (Scheme_Object*)t, env);
5272   s = scheme_intern_symbol("int32");
5273   t = (ctype_struct*)scheme_malloc_tagged(sizeof(ctype_struct));
5274   t->so.type = ctype_tag;
5275   t->basetype = (s);
5276   t->scheme_to_c = ((Scheme_Object*)(void*)(&ffi_type_sint32));
5277   t->c_to_scheme = ((Scheme_Object*)FOREIGN_int32);
5278   REGISTER_SO(scheme_int32_ctype);
5279   scheme_int32_ctype = (Scheme_Object *)t;
5280   scheme_addto_prim_instance("_int32", (Scheme_Object*)t, env);
5281   s = scheme_intern_symbol("uint32");
5282   t = (ctype_struct*)scheme_malloc_tagged(sizeof(ctype_struct));
5283   t->so.type = ctype_tag;
5284   t->basetype = (s);
5285   t->scheme_to_c = ((Scheme_Object*)(void*)(&ffi_type_uint32));
5286   t->c_to_scheme = ((Scheme_Object*)FOREIGN_uint32);
5287   REGISTER_SO(scheme_uint32_ctype);
5288   scheme_uint32_ctype = (Scheme_Object *)t;
5289   scheme_addto_prim_instance("_uint32", (Scheme_Object*)t, env);
5290   s = scheme_intern_symbol("int64");
5291   t = (ctype_struct*)scheme_malloc_tagged(sizeof(ctype_struct));
5292   t->so.type = ctype_tag;
5293   t->basetype = (s);
5294   t->scheme_to_c = ((Scheme_Object*)(void*)(&ffi_type_sint64));
5295   t->c_to_scheme = ((Scheme_Object*)FOREIGN_int64);
5296   REGISTER_SO(scheme_int64_ctype);
5297   scheme_int64_ctype = (Scheme_Object *)t;
5298   scheme_addto_prim_instance("_int64", (Scheme_Object*)t, env);
5299   s = scheme_intern_symbol("uint64");
5300   t = (ctype_struct*)scheme_malloc_tagged(sizeof(ctype_struct));
5301   t->so.type = ctype_tag;
5302   t->basetype = (s);
5303   t->scheme_to_c = ((Scheme_Object*)(void*)(&ffi_type_uint64));
5304   t->c_to_scheme = ((Scheme_Object*)FOREIGN_uint64);
5305   REGISTER_SO(scheme_uint64_ctype);
5306   scheme_uint64_ctype = (Scheme_Object *)t;
5307   scheme_addto_prim_instance("_uint64", (Scheme_Object*)t, env);
5308   s = scheme_intern_symbol("fixint");
5309   t = (ctype_struct*)scheme_malloc_tagged(sizeof(ctype_struct));
5310   t->so.type = ctype_tag;
5311   t->basetype = (s);
5312   t->scheme_to_c = ((Scheme_Object*)(void*)(&ffi_type_sint32));
5313   t->c_to_scheme = ((Scheme_Object*)FOREIGN_fixint);
5314   scheme_addto_prim_instance("_fixint", (Scheme_Object*)t, env);
5315   s = scheme_intern_symbol("ufixint");
5316   t = (ctype_struct*)scheme_malloc_tagged(sizeof(ctype_struct));
5317   t->so.type = ctype_tag;
5318   t->basetype = (s);
5319   t->scheme_to_c = ((Scheme_Object*)(void*)(&ffi_type_uint32));
5320   t->c_to_scheme = ((Scheme_Object*)FOREIGN_ufixint);
5321   scheme_addto_prim_instance("_ufixint", (Scheme_Object*)t, env);
5322   s = scheme_intern_symbol("fixnum");
5323   t = (ctype_struct*)scheme_malloc_tagged(sizeof(ctype_struct));
5324   t->so.type = ctype_tag;
5325   t->basetype = (s);
5326   t->scheme_to_c = ((Scheme_Object*)(void*)(&ffi_type_smzintptr));
5327   t->c_to_scheme = ((Scheme_Object*)FOREIGN_fixnum);
5328   scheme_addto_prim_instance("_fixnum", (Scheme_Object*)t, env);
5329   s = scheme_intern_symbol("ufixnum");
5330   t = (ctype_struct*)scheme_malloc_tagged(sizeof(ctype_struct));
5331   t->so.type = ctype_tag;
5332   t->basetype = (s);
5333   t->scheme_to_c = ((Scheme_Object*)(void*)(&ffi_type_umzintptr));
5334   t->c_to_scheme = ((Scheme_Object*)FOREIGN_ufixnum);
5335   scheme_addto_prim_instance("_ufixnum", (Scheme_Object*)t, env);
5336   s = scheme_intern_symbol("float");
5337   t = (ctype_struct*)scheme_malloc_tagged(sizeof(ctype_struct));
5338   t->so.type = ctype_tag;
5339   t->basetype = (s);
5340   t->scheme_to_c = ((Scheme_Object*)(void*)(&ffi_type_float));
5341   t->c_to_scheme = ((Scheme_Object*)FOREIGN_float);
5342   REGISTER_SO(scheme_float_ctype);
5343   scheme_float_ctype = (Scheme_Object *)t;
5344   scheme_addto_prim_instance("_float", (Scheme_Object*)t, env);
5345   s = scheme_intern_symbol("double");
5346   t = (ctype_struct*)scheme_malloc_tagged(sizeof(ctype_struct));
5347   t->so.type = ctype_tag;
5348   t->basetype = (s);
5349   t->scheme_to_c = ((Scheme_Object*)(void*)(&ffi_type_double));
5350   t->c_to_scheme = ((Scheme_Object*)FOREIGN_double);
5351   REGISTER_SO(scheme_double_ctype);
5352   scheme_double_ctype = (Scheme_Object *)t;
5353   scheme_addto_prim_instance("_double", (Scheme_Object*)t, env);
5354   s = scheme_intern_symbol("longdouble");
5355   t = (ctype_struct*)scheme_malloc_tagged(sizeof(ctype_struct));
5356   t->so.type = ctype_tag;
5357   t->basetype = (s);
5358   t->scheme_to_c = ((Scheme_Object*)(void*)(&ffi_type_slongdouble));
5359   t->c_to_scheme = ((Scheme_Object*)FOREIGN_longdouble);
5360   scheme_addto_prim_instance("_longdouble", (Scheme_Object*)t, env);
5361   s = scheme_intern_symbol("double*");
5362   t = (ctype_struct*)scheme_malloc_tagged(sizeof(ctype_struct));
5363   t->so.type = ctype_tag;
5364   t->basetype = (s);
5365   t->scheme_to_c = ((Scheme_Object*)(void*)(&ffi_type_double));
5366   t->c_to_scheme = ((Scheme_Object*)FOREIGN_doubleS);
5367   scheme_addto_prim_instance("_double*", (Scheme_Object*)t, env);
5368   s = scheme_intern_symbol("bool");
5369   t = (ctype_struct*)scheme_malloc_tagged(sizeof(ctype_struct));
5370   t->so.type = ctype_tag;
5371   t->basetype = (s);
5372   t->scheme_to_c = ((Scheme_Object*)(void*)(&ffi_type_sint));
5373   t->c_to_scheme = ((Scheme_Object*)FOREIGN_bool);
5374   scheme_addto_prim_instance("_bool", (Scheme_Object*)t, env);
5375   s = scheme_intern_symbol("stdbool");
5376   t = (ctype_struct*)scheme_malloc_tagged(sizeof(ctype_struct));
5377   t->so.type = ctype_tag;
5378   t->basetype = (s);
5379   t->scheme_to_c = ((Scheme_Object*)(void*)(&ffi_type_stdbool));
5380   t->c_to_scheme = ((Scheme_Object*)FOREIGN_stdbool);
5381   scheme_addto_prim_instance("_stdbool", (Scheme_Object*)t, env);
5382   s = scheme_intern_symbol("string/ucs-4");
5383   t = (ctype_struct*)scheme_malloc_tagged(sizeof(ctype_struct));
5384   t->so.type = ctype_tag;
5385   t->basetype = (s);
5386   t->scheme_to_c = ((Scheme_Object*)(void*)(&ffi_type_gcpointer));
5387   t->c_to_scheme = ((Scheme_Object*)FOREIGN_string_ucs_4);
5388   scheme_addto_prim_instance("_string/ucs-4", (Scheme_Object*)t, env);
5389   s = scheme_intern_symbol("string/utf-16");
5390   t = (ctype_struct*)scheme_malloc_tagged(sizeof(ctype_struct));
5391   t->so.type = ctype_tag;
5392   t->basetype = (s);
5393   t->scheme_to_c = ((Scheme_Object*)(void*)(&ffi_type_gcpointer));
5394   t->c_to_scheme = ((Scheme_Object*)FOREIGN_string_utf_16);
5395   scheme_addto_prim_instance("_string/utf-16", (Scheme_Object*)t, env);
5396   s = scheme_intern_symbol("bytes");
5397   t = (ctype_struct*)scheme_malloc_tagged(sizeof(ctype_struct));
5398   t->so.type = ctype_tag;
5399   t->basetype = (s);
5400   t->scheme_to_c = ((Scheme_Object*)(void*)(&ffi_type_gcpointer));
5401   t->c_to_scheme = ((Scheme_Object*)FOREIGN_bytes);
5402   scheme_addto_prim_instance("_bytes", (Scheme_Object*)t, env);
5403   s = scheme_intern_symbol("path");
5404   t = (ctype_struct*)scheme_malloc_tagged(sizeof(ctype_struct));
5405   t->so.type = ctype_tag;
5406   t->basetype = (s);
5407   t->scheme_to_c = ((Scheme_Object*)(void*)(&ffi_type_gcpointer));
5408   t->c_to_scheme = ((Scheme_Object*)FOREIGN_path);
5409   scheme_addto_prim_instance("_path", (Scheme_Object*)t, env);
5410   s = scheme_intern_symbol("symbol");
5411   t = (ctype_struct*)scheme_malloc_tagged(sizeof(ctype_struct));
5412   t->so.type = ctype_tag;
5413   t->basetype = (s);
5414   t->scheme_to_c = ((Scheme_Object*)(void*)(&ffi_type_pointer));
5415   t->c_to_scheme = ((Scheme_Object*)FOREIGN_symbol);
5416   scheme_addto_prim_instance("_symbol", (Scheme_Object*)t, env);
5417   s = scheme_intern_symbol("pointer");
5418   t = (ctype_struct*)scheme_malloc_tagged(sizeof(ctype_struct));
5419   t->so.type = ctype_tag;
5420   t->basetype = (s);
5421   t->scheme_to_c = ((Scheme_Object*)(void*)(&ffi_type_pointer));
5422   t->c_to_scheme = ((Scheme_Object*)FOREIGN_pointer);
5423   REGISTER_SO(scheme_pointer_ctype);
5424   scheme_pointer_ctype = (Scheme_Object *)t;
5425   scheme_addto_prim_instance("_pointer", (Scheme_Object*)t, env);
5426   s = scheme_intern_symbol("gcpointer");
5427   t = (ctype_struct*)scheme_malloc_tagged(sizeof(ctype_struct));
5428   t->so.type = ctype_tag;
5429   t->basetype = (s);
5430   t->scheme_to_c = ((Scheme_Object*)(void*)(&ffi_type_gcpointer));
5431   t->c_to_scheme = ((Scheme_Object*)FOREIGN_gcpointer);
5432   scheme_addto_prim_instance("_gcpointer", (Scheme_Object*)t, env);
5433   s = scheme_intern_symbol("scheme");
5434   t = (ctype_struct*)scheme_malloc_tagged(sizeof(ctype_struct));
5435   t->so.type = ctype_tag;
5436   t->basetype = (s);
5437   t->scheme_to_c = ((Scheme_Object*)(void*)(&ffi_type_gcpointer));
5438   t->c_to_scheme = ((Scheme_Object*)FOREIGN_scheme);
5439   scheme_addto_prim_instance("_scheme", (Scheme_Object*)t, env);
5440   s = scheme_intern_symbol("fpointer");
5441   t = (ctype_struct*)scheme_malloc_tagged(sizeof(ctype_struct));
5442   t->so.type = ctype_tag;
5443   t->basetype = (s);
5444   t->scheme_to_c = ((Scheme_Object*)(void*)(&ffi_type_pointer));
5445   t->c_to_scheme = ((Scheme_Object*)FOREIGN_fpointer);
5446   scheme_addto_prim_instance("_fpointer", (Scheme_Object*)t, env);
5447   scheme_addto_prim_instance("prop:cpointer", scheme_cpointer_property, env);
5448   scheme_restore_prim_instance(env);
5449 }
5450 
5451 /*****************************************************************************/
5452 
5453 #else /* DONT_USE_FOREIGN */
5454 
scheme_is_cpointer(Scheme_Object * cp)5455 int scheme_is_cpointer(Scheme_Object *cp)
5456 {
5457   return (SCHEME_FALSEP(cp)
5458           || SCHEME_CPTRP(x)
5459           || SCHEME_BYTE_STRINGP(x)
5460           || (SCHEME_CHAPERONE_STRUCTP(cp)
5461               && scheme_struct_type_property_ref(scheme_cpointer_property, cp)));
5462 }
5463 
unimplemented(int argc,Scheme_Object ** argv,Scheme_Object * who)5464 static Scheme_Object *unimplemented(int argc, Scheme_Object **argv, Scheme_Object *who)
5465 {
5466   scheme_signal_error("%s: foreign interface not supported for this platform",
5467                       ((Scheme_Primitive_Proc *)who)->name);
5468   return NULL;
5469 }
5470 
foreign_compiler_sizeof(int argc,Scheme_Object ** argv)5471 static Scheme_Object *foreign_compiler_sizeof(int argc, Scheme_Object **argv)
5472 {
5473   return scheme_make_integer(4);
5474 }
5475 
foreign_make_ctype(int argc,Scheme_Object ** argv)5476 static Scheme_Object *foreign_make_ctype(int argc, Scheme_Object **argv)
5477 {
5478   return scheme_false;
5479 }
5480 
foreign_make_late_will_executor(int argc,Scheme_Object * argv[])5481 static Scheme_Object *foreign_make_late_will_executor(int argc, Scheme_Object *argv[])
5482 {
5483   return scheme_make_late_will_executor();
5484 }
5485 
scheme_init_foreign(Scheme_Env * env)5486 void scheme_init_foreign(Scheme_Env *env)
5487 {
5488   /* Create a dummy module. */
5489   scheme_switch_prim_instance(env, "#%foreign");
5490   scheme_addto_primitive_instance("ffi-lib?",
5491    scheme_make_immed_prim((Scheme_Prim *)unimplemented, "ffi-lib?", 1, 1), env);
5492   scheme_addto_primitive_instance("ffi-lib",
5493    scheme_make_noncm_prim((Scheme_Prim *)unimplemented, "ffi-lib", 1, 3), env);
5494   scheme_addto_primitive_instance("ffi-lib-name",
5495    scheme_make_noncm_prim((Scheme_Prim *)unimplemented, "ffi-lib-name", 1, 1), env);
5496   scheme_addto_primitive_instance("ffi-lib-unload",
5497    scheme_make_noncm_prim((Scheme_Prim *)unimplemented, "ffi-lib-unload", 1, 1), env);
5498   scheme_addto_primitive_instance("ffi-obj?",
5499    scheme_make_immed_prim((Scheme_Prim *)unimplemented, "ffi-obj?", 1, 1), env);
5500   scheme_addto_primitive_instance("ffi-obj",
5501    scheme_make_noncm_prim((Scheme_Prim *)unimplemented, "ffi-obj", 2, 2), env);
5502   scheme_addto_primitive_instance("ffi-obj-lib",
5503    scheme_make_immed_prim((Scheme_Prim *)unimplemented, "ffi-obj-lib", 1, 1), env);
5504   scheme_addto_primitive_instance("ffi-obj-name",
5505    scheme_make_immed_prim((Scheme_Prim *)unimplemented, "ffi-obj-name", 1, 1), env);
5506   scheme_addto_primitive_instance("ctype?",
5507    scheme_make_immed_prim((Scheme_Prim *)unimplemented, "ctype?", 1, 1), env);
5508   scheme_addto_primitive_instance("ctype-basetype",
5509    scheme_make_immed_prim((Scheme_Prim *)unimplemented, "ctype-basetype", 1, 1), env);
5510   scheme_addto_primitive_instance("ctype-scheme->c",
5511    scheme_make_immed_prim((Scheme_Prim *)unimplemented, "ctype-scheme->c", 1, 1), env);
5512   scheme_addto_primitive_instance("ctype-c->scheme",
5513    scheme_make_immed_prim((Scheme_Prim *)unimplemented, "ctype-c->scheme", 1, 1), env);
5514   scheme_addto_primitive_instance("make-ctype",
5515    scheme_make_noncm_prim((Scheme_Prim *)foreign_make_ctype, "make-ctype", 3, 3), env);
5516   scheme_addto_primitive_instance("make-cstruct-type",
5517    scheme_make_noncm_prim((Scheme_Prim *)unimplemented, "make-cstruct-type", 1, 4), env);
5518   scheme_addto_primitive_instance("make-array-type",
5519    scheme_make_noncm_prim((Scheme_Prim *)unimplemented, "make-array-type", 2, 2), env);
5520   scheme_addto_primitive_instance("make-union-type",
5521    scheme_make_noncm_prim((Scheme_Prim *)unimplemented, "make-union-type", 1, -1), env);
5522   scheme_addto_primitive_instance("ffi-callback?",
5523    scheme_make_immed_prim((Scheme_Prim *)unimplemented, "ffi-callback?", 1, 1), env);
5524   scheme_addto_primitive_instance("cpointer?",
5525    scheme_make_immed_prim((Scheme_Prim *)unimplemented, "cpointer?", 1, 1), env);
5526   scheme_addto_primitive_instance("cpointer-tag",
5527    scheme_make_inline_noncm_prim((Scheme_Prim *)unimplemented, "cpointer-tag", 1, 1), env);
5528   scheme_addto_primitive_instance("set-cpointer-tag!",
5529    scheme_make_inline_noncm_prim((Scheme_Prim *)unimplemented, "set-cpointer-tag!", 2, 2), env);
5530   scheme_addto_primitive_instance("cpointer-gcable?",
5531    scheme_make_noncm_prim((Scheme_Prim *)unimplemented, "cpointer-gcable?", 1, 1), env);
5532   scheme_addto_primitive_instance("ctype-sizeof",
5533    scheme_make_immed_prim((Scheme_Prim *)unimplemented, "ctype-sizeof", 1, 1), env);
5534   scheme_addto_primitive_instance("ctype-alignof",
5535    scheme_make_immed_prim((Scheme_Prim *)unimplemented, "ctype-alignof", 1, 1), env);
5536   scheme_addto_primitive_instance("compiler-sizeof",
5537    scheme_make_immed_prim((Scheme_Prim *)foreign_compiler_sizeof, "compiler-sizeof", 1, 1), env);
5538   scheme_addto_primitive_instance("malloc",
5539    scheme_make_noncm_prim((Scheme_Prim *)unimplemented, "malloc", 1, 5), env);
5540   scheme_addto_primitive_instance("end-stubborn-change",
5541    scheme_make_noncm_prim((Scheme_Prim *)unimplemented, "end-stubborn-change", 1, 1), env);
5542   scheme_addto_primitive_instance("free",
5543    scheme_make_noncm_prim((Scheme_Prim *)unimplemented, "free", 1, 1), env);
5544   scheme_addto_primitive_instance("malloc-immobile-cell",
5545    scheme_make_immed_prim((Scheme_Prim *)unimplemented, "malloc-immobile-cell", 1, 1), env);
5546   scheme_addto_primitive_instance("free-immobile-cell",
5547    scheme_make_noncm_prim((Scheme_Prim *)unimplemented, "free-immobile-cell", 1, 1), env);
5548   scheme_addto_primitive_instance("ptr-add",
5549    scheme_make_noncm_prim((Scheme_Prim *)unimplemented, "ptr-add", 2, 3), env);
5550   scheme_addto_primitive_instance("ptr-add!",
5551    scheme_make_noncm_prim((Scheme_Prim *)unimplemented, "ptr-add!", 2, 3), env);
5552   scheme_addto_primitive_instance("offset-ptr?",
5553    scheme_make_noncm_prim((Scheme_Prim *)unimplemented, "offset-ptr?", 1, 1), env);
5554   scheme_addto_primitive_instance("ptr-offset",
5555    scheme_make_noncm_prim((Scheme_Prim *)unimplemented, "ptr-offset", 1, 1), env);
5556   scheme_addto_primitive_instance("set-ptr-offset!",
5557    scheme_make_noncm_prim((Scheme_Prim *)unimplemented, "set-ptr-offset!", 2, 3), env);
5558   scheme_addto_primitive_instance("vector->cpointer",
5559    scheme_make_immed_prim((Scheme_Prim *)unimplemented, "vector->cpointer", 1, 1), env);
5560   scheme_addto_primitive_instance("flvector->cpointer",
5561    scheme_make_immed_prim((Scheme_Prim *)unimplemented, "flvector->cpointer", 1, 1), env);
5562   scheme_addto_primitive_instance("extflvector->cpointer",
5563    scheme_make_immed_prim((Scheme_Prim *)unimplemented, "extflvector->cpointer", 1, 1), env);
5564   scheme_addto_primitive_instance("memset",
5565    scheme_make_noncm_prim((Scheme_Prim *)unimplemented, "memset", 3, 5), env);
5566   scheme_addto_primitive_instance("memmove",
5567    scheme_make_noncm_prim((Scheme_Prim *)unimplemented, "memmove", 3, 6), env);
5568   scheme_addto_primitive_instance("memcpy",
5569    scheme_make_noncm_prim((Scheme_Prim *)unimplemented, "memcpy", 3, 6), env);
5570   scheme_addto_primitive_instance("ptr-ref",
5571    scheme_make_inline_noncm_prim((Scheme_Prim *)unimplemented, "ptr-ref", 2, 4), env);
5572   scheme_addto_primitive_instance("ptr-set!",
5573    scheme_make_inline_noncm_prim((Scheme_Prim *)unimplemented, "ptr-set!", 3, 5), env);
5574   scheme_addto_primitive_instance("ptr-equal?",
5575    scheme_make_noncm_prim((Scheme_Prim *)unimplemented, "ptr-equal?", 2, 2), env);
5576   scheme_addto_primitive_instance("make-sized-byte-string",
5577    scheme_make_noncm_prim((Scheme_Prim *)unimplemented, "make-sized-byte-string", 2, 2), env);
5578   scheme_addto_primitive_instance("ffi-call",
5579    scheme_make_noncm_prim((Scheme_Prim *)unimplemented, "ffi-call", 3, 10), env);
5580   scheme_addto_primitive_instance("ffi-call-maker",
5581    scheme_make_noncm_prim((Scheme_Prim *)unimplemented, "ffi-call-maker", 2, 9), env);
5582   scheme_addto_primitive_instance("ffi-callback",
5583    scheme_make_noncm_prim((Scheme_Prim *)unimplemented, "ffi-callback", 3, 6), env);
5584   scheme_addto_primitive_instance("ffi-callback-maker",
5585    scheme_make_noncm_prim((Scheme_Prim *)unimplemented, "ffi-callback-maker", 2, 6), env);
5586   scheme_addto_primitive_instance("saved-errno",
5587    scheme_make_immed_prim((Scheme_Prim *)unimplemented, "saved-errno", 0, 1), env);
5588   scheme_addto_primitive_instance("lookup-errno",
5589    scheme_make_immed_prim((Scheme_Prim *)unimplemented, "lookup-errno", 1, 1), env);
5590   scheme_addto_primitive_instance("make-late-will-executor",
5591    scheme_make_immed_prim((Scheme_Prim *)foreign_make_late_will_executor, "make-late-will-executor", 0, 0), env);
5592   scheme_addto_primitive_instance("make-late-weak-box",
5593    scheme_make_immed_prim((Scheme_Prim *)unimplemented, "make-late-weak-box", 1, 1), env);
5594   scheme_addto_primitive_instance("make-late-weak-hasheq",
5595    scheme_make_immed_prim((Scheme_Prim *)unimplemented, "make-late-weak-hasheq", 0, 0), env);
5596   scheme_add_global_constant("_void", scheme_false, env);
5597   scheme_add_global_constant("_int8", scheme_false, env);
5598   scheme_add_global_constant("_uint8", scheme_false, env);
5599   scheme_add_global_constant("_int16", scheme_false, env);
5600   scheme_add_global_constant("_uint16", scheme_false, env);
5601   scheme_add_global_constant("_int32", scheme_false, env);
5602   scheme_add_global_constant("_uint32", scheme_false, env);
5603   scheme_add_global_constant("_int64", scheme_false, env);
5604   scheme_add_global_constant("_uint64", scheme_false, env);
5605   scheme_add_global_constant("_fixint", scheme_false, env);
5606   scheme_add_global_constant("_ufixint", scheme_false, env);
5607   scheme_add_global_constant("_fixnum", scheme_false, env);
5608   scheme_add_global_constant("_ufixnum", scheme_false, env);
5609   scheme_add_global_constant("_float", scheme_false, env);
5610   scheme_add_global_constant("_double", scheme_false, env);
5611   scheme_add_global_constant("_longdouble", scheme_false, env);
5612   scheme_add_global_constant("_double*", scheme_false, env);
5613   scheme_add_global_constant("_bool", scheme_false, env);
5614   scheme_add_global_constant("_stdbool", scheme_false, env);
5615   scheme_add_global_constant("_string/ucs-4", scheme_false, env);
5616   scheme_add_global_constant("_string/utf-16", scheme_false, env);
5617   scheme_add_global_constant("_bytes", scheme_false, env);
5618   scheme_add_global_constant("_path", scheme_false, env);
5619   scheme_add_global_constant("_symbol", scheme_false, env);
5620   scheme_add_global_constant("_pointer", scheme_false, env);
5621   scheme_add_global_constant("_gcpointer", scheme_false, env);
5622   scheme_add_global_constant("_scheme", scheme_false, env);
5623   scheme_add_global_constant("_fpointer", scheme_false, env);
5624   scheme_addto_primitive_instance("prop:cpointer", scheme_cpointer_property, env);
5625   scheme_restore_prim_instance(env);
5626 }
5627 
5628 #endif
5629