174
218
else if (small_struct)
175
219
ecif.rvalue = &temp;
222
/* Largest case is double x 4. */
223
ecif.rvalue = alloca(32);
177
226
ecif.rvalue = rvalue;
179
228
switch (cif->abi)
182
ffi_call_SYSV(ffi_prep_args, &ecif, cif->bytes, cif->flags, ecif.rvalue,
231
ffi_call_SYSV (fn, &ecif, cif->bytes, cif->flags, ecif.rvalue);
235
ffi_call_VFP (fn, &ecif, cif->bytes, cif->flags, ecif.rvalue);
190
242
if (small_struct)
191
243
memcpy (rvalue, &temp, cif->rtype->size);
245
memcpy (rvalue, ecif.rvalue, cif->rtype->size);
194
248
/** private members **/
196
250
static void ffi_prep_incoming_args_SYSV (char *stack, void **ret,
197
void** args, ffi_cif* cif);
251
void** args, ffi_cif* cif, float *vfp_stack);
199
253
void ffi_closure_SYSV (ffi_closure *);
255
void ffi_closure_VFP (ffi_closure *);
201
257
/* This function is jumped to by the trampoline */
204
ffi_closure_SYSV_inner (closure, respp, args)
260
ffi_closure_SYSV_inner (closure, respp, args, vfp_args)
205
261
ffi_closure *closure;
209
266
// our various things...
274
341
/* How to make a trampoline. */
343
#if FFI_EXEC_TRAMPOLINE_TABLE
345
#include <mach/mach.h>
350
extern void *ffi_closure_trampoline_table_page;
352
typedef struct ffi_trampoline_table ffi_trampoline_table;
353
typedef struct ffi_trampoline_table_entry ffi_trampoline_table_entry;
355
struct ffi_trampoline_table {
356
/* contigious writable and executable pages */
357
vm_address_t config_page;
358
vm_address_t trampoline_page;
360
/* free list tracking */
362
ffi_trampoline_table_entry *free_list;
363
ffi_trampoline_table_entry *free_list_pool;
365
ffi_trampoline_table *prev;
366
ffi_trampoline_table *next;
369
struct ffi_trampoline_table_entry {
370
void *(*trampoline)();
371
ffi_trampoline_table_entry *next;
374
/* Override the standard architecture trampoline size */
376
#undef FFI_TRAMPOLINE_SIZE
377
#define FFI_TRAMPOLINE_SIZE 12
379
/* The trampoline configuration is placed at 4080 bytes prior to the trampoline's entry point */
380
#define FFI_TRAMPOLINE_CODELOC_CONFIG(codeloc) ((void **) (((uint8_t *) codeloc) - 4080));
382
/* The first 16 bytes of the config page are unused, as they are unaddressable from the trampoline page. */
383
#define FFI_TRAMPOLINE_CONFIG_PAGE_OFFSET 16
385
/* Total number of trampolines that fit in one trampoline table */
386
#define FFI_TRAMPOLINE_COUNT ((PAGE_SIZE - FFI_TRAMPOLINE_CONFIG_PAGE_OFFSET) / FFI_TRAMPOLINE_SIZE)
388
static pthread_mutex_t ffi_trampoline_lock = PTHREAD_MUTEX_INITIALIZER;
389
static ffi_trampoline_table *ffi_trampoline_tables = NULL;
391
static ffi_trampoline_table *
392
ffi_trampoline_table_alloc ()
394
ffi_trampoline_table *table = NULL;
396
/* Loop until we can allocate two contigious pages */
397
while (table == NULL) {
398
vm_address_t config_page = 0x0;
401
/* Try to allocate two pages */
402
kt = vm_allocate (mach_task_self (), &config_page, PAGE_SIZE*2, VM_FLAGS_ANYWHERE);
403
if (kt != KERN_SUCCESS) {
404
fprintf(stderr, "vm_allocate() failure: %d at %s:%d\n", kt, __FILE__, __LINE__);
408
/* Now drop the second half of the allocation to make room for the trampoline table */
409
vm_address_t trampoline_page = config_page+PAGE_SIZE;
410
kt = vm_deallocate (mach_task_self (), trampoline_page, PAGE_SIZE);
411
if (kt != KERN_SUCCESS) {
412
fprintf(stderr, "vm_deallocate() failure: %d at %s:%d\n", kt, __FILE__, __LINE__);
416
/* Remap the trampoline table to directly follow the config page */
420
kt = vm_remap (mach_task_self (), &trampoline_page, PAGE_SIZE, 0x0, FALSE, mach_task_self (), (vm_address_t) &ffi_closure_trampoline_table_page, FALSE, &cur_prot, &max_prot, VM_INHERIT_SHARE);
422
/* If we lost access to the destination trampoline page, drop our config allocation mapping and retry */
423
if (kt != KERN_SUCCESS) {
424
/* Log unexpected failures */
425
if (kt != KERN_NO_SPACE) {
426
fprintf(stderr, "vm_remap() failure: %d at %s:%d\n", kt, __FILE__, __LINE__);
429
vm_deallocate (mach_task_self (), config_page, PAGE_SIZE);
433
/* We have valid trampoline and config pages */
434
table = calloc (1, sizeof(ffi_trampoline_table));
435
table->free_count = FFI_TRAMPOLINE_COUNT;
436
table->config_page = config_page;
437
table->trampoline_page = trampoline_page;
439
/* Create and initialize the free list */
440
table->free_list_pool = calloc(FFI_TRAMPOLINE_COUNT, sizeof(ffi_trampoline_table_entry));
443
for (i = 0; i < table->free_count; i++) {
444
ffi_trampoline_table_entry *entry = &table->free_list_pool[i];
445
entry->trampoline = (void *) (table->trampoline_page + (i * FFI_TRAMPOLINE_SIZE));
447
if (i < table->free_count - 1)
448
entry->next = &table->free_list_pool[i+1];
451
table->free_list = table->free_list_pool;
458
ffi_closure_alloc (size_t size, void **code)
460
/* Create the closure */
461
ffi_closure *closure = malloc(size);
465
pthread_mutex_lock(&ffi_trampoline_lock);
467
/* Check for an active trampoline table with available entries. */
468
ffi_trampoline_table *table = ffi_trampoline_tables;
469
if (table == NULL || table->free_list == NULL) {
470
table = ffi_trampoline_table_alloc ();
476
/* Insert the new table at the top of the list */
477
table->next = ffi_trampoline_tables;
478
if (table->next != NULL)
479
table->next->prev = table;
481
ffi_trampoline_tables = table;
484
/* Claim the free entry */
485
ffi_trampoline_table_entry *entry = ffi_trampoline_tables->free_list;
486
ffi_trampoline_tables->free_list = entry->next;
487
ffi_trampoline_tables->free_count--;
490
pthread_mutex_unlock(&ffi_trampoline_lock);
492
/* Initialize the return values */
493
*code = entry->trampoline;
494
closure->trampoline_table = table;
495
closure->trampoline_table_entry = entry;
501
ffi_closure_free (void *ptr)
503
ffi_closure *closure = ptr;
505
pthread_mutex_lock(&ffi_trampoline_lock);
507
/* Fetch the table and entry references */
508
ffi_trampoline_table *table = closure->trampoline_table;
509
ffi_trampoline_table_entry *entry = closure->trampoline_table_entry;
511
/* Return the entry to the free list */
512
entry->next = table->free_list;
513
table->free_list = entry;
516
/* If all trampolines within this table are free, and at least one other table exists, deallocate
518
if (table->free_count == FFI_TRAMPOLINE_COUNT && ffi_trampoline_tables != table) {
519
/* Remove from the list */
520
if (table->prev != NULL)
521
table->prev->next = table->next;
523
if (table->next != NULL)
524
table->next->prev = table->prev;
526
/* Deallocate pages */
528
kt = vm_deallocate (mach_task_self (), table->config_page, PAGE_SIZE);
529
if (kt != KERN_SUCCESS)
530
fprintf(stderr, "vm_deallocate() failure: %d at %s:%d\n", kt, __FILE__, __LINE__);
532
kt = vm_deallocate (mach_task_self (), table->trampoline_page, PAGE_SIZE);
533
if (kt != KERN_SUCCESS)
534
fprintf(stderr, "vm_deallocate() failure: %d at %s:%d\n", kt, __FILE__, __LINE__);
536
/* Deallocate free list */
537
free (table->free_list_pool);
539
} else if (ffi_trampoline_tables != table) {
540
/* Otherwise, bump this table to the top of the list */
542
table->next = ffi_trampoline_tables;
543
if (ffi_trampoline_tables != NULL)
544
ffi_trampoline_tables->prev = table;
546
ffi_trampoline_tables = table;
549
pthread_mutex_unlock (&ffi_trampoline_lock);
551
/* Free the closure */
276
557
#define FFI_INIT_TRAMPOLINE(TRAMP,FUN,CTX) \
277
558
({ unsigned char *__tramp = (unsigned char*)(TRAMP); \
278
559
unsigned int __fun = (unsigned int)(FUN); \
298
FFI_ASSERT (cif->abi == FFI_SYSV);
580
void (*closure_func)(ffi_closure*) = NULL;
582
if (cif->abi == FFI_SYSV)
583
closure_func = &ffi_closure_SYSV;
584
else if (cif->abi == FFI_VFP)
585
closure_func = &ffi_closure_VFP;
589
#if FFI_EXEC_TRAMPOLINE_TABLE
590
void **config = FFI_TRAMPOLINE_CODELOC_CONFIG(codeloc);
592
config[1] = closure_func;
300
594
FFI_INIT_TRAMPOLINE (&closure->tramp[0], \
304
599
closure->cif = cif;
305
600
closure->user_data = user_data;
306
601
closure->fun = fun;
606
/* Below are routines for VFP hard-float support. */
608
static int rec_vfp_type_p (ffi_type *t, int *elt, int *elnum)
613
case FFI_TYPE_DOUBLE:
614
*elt = (int) t->type;
618
case FFI_TYPE_STRUCT_VFP_FLOAT:
619
*elt = FFI_TYPE_FLOAT;
620
*elnum = t->size / sizeof (float);
623
case FFI_TYPE_STRUCT_VFP_DOUBLE:
624
*elt = FFI_TYPE_DOUBLE;
625
*elnum = t->size / sizeof (double);
628
case FFI_TYPE_STRUCT:;
630
int base_elt = 0, total_elnum = 0;
631
ffi_type **el = t->elements;
634
int el_elt = 0, el_elnum = 0;
635
if (! rec_vfp_type_p (*el, &el_elt, &el_elnum)
636
|| (base_elt && base_elt != el_elt)
637
|| total_elnum + el_elnum > 4)
640
total_elnum += el_elnum;
643
*elnum = total_elnum;
652
static int vfp_type_p (ffi_type *t)
655
if (rec_vfp_type_p (t, &elt, &elnum))
657
if (t->type == FFI_TYPE_STRUCT)
662
t->type = (elt == FFI_TYPE_FLOAT
663
? FFI_TYPE_STRUCT_VFP_FLOAT
664
: FFI_TYPE_STRUCT_VFP_DOUBLE);
666
return (int) t->type;
671
static void place_vfp_arg (ffi_cif *cif, ffi_type *t)
673
int reg = cif->vfp_reg_free;
674
int nregs = t->size / sizeof (float);
675
int align = ((t->type == FFI_TYPE_STRUCT_VFP_FLOAT
676
|| t->type == FFI_TYPE_FLOAT) ? 1 : 2);
677
/* Align register number. */
678
if ((reg & 1) && align == 2)
680
while (reg + nregs <= 16)
683
for (s = reg; s < reg + nregs; s++)
685
new_used |= (1 << s);
686
if (cif->vfp_used & (1 << s))
692
/* Found regs to allocate. */
693
cif->vfp_used |= new_used;
694
cif->vfp_args[cif->vfp_nargs++] = reg;
696
/* Update vfp_reg_free. */
697
if (cif->vfp_used & (1 << cif->vfp_reg_free))
700
while (cif->vfp_used & (1 << reg))
702
cif->vfp_reg_free = reg;
709
static void layout_vfp_args (ffi_cif *cif)
712
/* Init VFP fields */
715
cif->vfp_reg_free = 0;
716
memset (cif->vfp_args, -1, 16); /* Init to -1. */
718
for (i = 0; i < cif->nargs; i++)
720
ffi_type *t = cif->arg_types[i];
722
place_vfp_arg (cif, t);