1/* -----------------------------------------------------------------------
2   ffi.c - Copyright (c) 2011 Timothy Wall
3           Copyright (c) 2011 Plausible Labs Cooperative, Inc.
4           Copyright (c) 2011 Anthony Green
5	   Copyright (c) 2011 Free Software Foundation
6           Copyright (c) 1998, 2008, 2011  Red Hat, Inc.
7
8   ARM Foreign Function Interface
9
10   Permission is hereby granted, free of charge, to any person obtaining
11   a copy of this software and associated documentation files (the
12   ``Software''), to deal in the Software without restriction, including
13   without limitation the rights to use, copy, modify, merge, publish,
14   distribute, sublicense, and/or sell copies of the Software, and to
15   permit persons to whom the Software is furnished to do so, subject to
16   the following conditions:
17
18   The above copyright notice and this permission notice shall be included
19   in all copies or substantial portions of the Software.
20
21   THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND,
22   EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
23   MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
24   NONINFRINGEMENT.  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
25   HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
26   WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
27   OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
28   DEALINGS IN THE SOFTWARE.
29   ----------------------------------------------------------------------- */
30
31#include <ffi.h>
32#include <ffi_common.h>
33
34#include <stdlib.h>
35
36/* Forward declares. */
37static int vfp_type_p (ffi_type *);
38static void layout_vfp_args (ffi_cif *);
39
40int ffi_prep_args_SYSV(char *stack, extended_cif *ecif, float *vfp_space);
41int ffi_prep_args_VFP(char *stack, extended_cif *ecif, float *vfp_space);
42
43static char* ffi_align(ffi_type **p_arg, char *argp)
44{
45  /* Align if necessary */
46  register size_t alignment = (*p_arg)->alignment;
47  if (alignment < 4)
48  {
49    alignment = 4;
50  }
51#ifdef _WIN32_WCE
52  if (alignment > 4)
53  {
54    alignment = 4;
55  }
56#endif
57  if ((alignment - 1) & (unsigned) argp)
58  {
59    argp = (char *) ALIGN(argp, alignment);
60  }
61
62  if ((*p_arg)->type == FFI_TYPE_STRUCT)
63  {
64    argp = (char *) ALIGN(argp, 4);
65  }
66  return argp;
67}
68
69static size_t ffi_put_arg(ffi_type **arg_type, void **arg, char *stack)
70{
71	register char* argp = stack;
72	register ffi_type **p_arg = arg_type;
73	register void **p_argv = arg;
74	register size_t z = (*p_arg)->size;
75  if (z < sizeof(int))
76    {
77		z = sizeof(int);
78		switch ((*p_arg)->type)
79      {
80      case FFI_TYPE_SINT8:
81        *(signed int *) argp = (signed int)*(SINT8 *)(* p_argv);
82        break;
83
84      case FFI_TYPE_UINT8:
85        *(unsigned int *) argp = (unsigned int)*(UINT8 *)(* p_argv);
86        break;
87
88      case FFI_TYPE_SINT16:
89        *(signed int *) argp = (signed int)*(SINT16 *)(* p_argv);
90        break;
91
92      case FFI_TYPE_UINT16:
93        *(unsigned int *) argp = (unsigned int)*(UINT16 *)(* p_argv);
94        break;
95
96      case FFI_TYPE_STRUCT:
97        memcpy(argp, *p_argv, (*p_arg)->size);
98        break;
99
100      default:
101        FFI_ASSERT(0);
102      }
103    }
104  else if (z == sizeof(int))
105    {
106		if ((*p_arg)->type == FFI_TYPE_FLOAT)
107			*(float *) argp = *(float *)(* p_argv);
108		else
109			*(unsigned int *) argp = (unsigned int)*(UINT32 *)(* p_argv);
110    }
111	else if (z == sizeof(double) && (*p_arg)->type == FFI_TYPE_DOUBLE)
112		{
113			*(double *) argp = *(double *)(* p_argv);
114		}
115  else
116    {
117      memcpy(argp, *p_argv, z);
118    }
119  return z;
120}
121/* ffi_prep_args is called by the assembly routine once stack space
122   has been allocated for the function's arguments
123
124   The vfp_space parameter is the load area for VFP regs, the return
125   value is cif->vfp_used (word bitset of VFP regs used for passing
126   arguments). These are only used for the VFP hard-float ABI.
127*/
128int ffi_prep_args_SYSV(char *stack, extended_cif *ecif, float *vfp_space)
129{
130  register unsigned int i;
131  register void **p_argv;
132  register char *argp;
133  register ffi_type **p_arg;
134  argp = stack;
135
136
137  if ( ecif->cif->flags == FFI_TYPE_STRUCT ) {
138    *(void **) argp = ecif->rvalue;
139    argp += 4;
140  }
141
142  p_argv = ecif->avalue;
143
144  for (i = ecif->cif->nargs, p_arg = ecif->cif->arg_types;
145       (i != 0);
146       i--, p_arg++, p_argv++)
147    {
148    argp = ffi_align(p_arg, argp);
149    argp += ffi_put_arg(p_arg, p_argv, argp);
150    }
151
152  return 0;
153}
154
155int ffi_prep_args_VFP(char *stack, extended_cif *ecif, float *vfp_space)
156{
157  register unsigned int i, vi = 0;
158  register void **p_argv;
159  register char *argp, *regp, *eo_regp;
160  register ffi_type **p_arg;
161  char stack_used = 0;
162  char done_with_regs = 0;
163  char is_vfp_type;
164
165  // make sure we are using FFI_VFP
166  FFI_ASSERT(ecif->cif->abi == FFI_VFP);
167
168  /* the first 4 words on the stack are used for values passed in core
169   * registers. */
170  regp = stack;
171  eo_regp = argp = regp + 16;
172
173
174  /* if the function returns an FFI_TYPE_STRUCT in memory, that address is
175   * passed in r0 to the function */
176  if ( ecif->cif->flags == FFI_TYPE_STRUCT ) {
177    *(void **) regp = ecif->rvalue;
178    regp += 4;
179  }
180
181  p_argv = ecif->avalue;
182
183  for (i = ecif->cif->nargs, p_arg = ecif->cif->arg_types;
184       (i != 0);
185       i--, p_arg++, p_argv++)
186    {
187      is_vfp_type = vfp_type_p (*p_arg);
188
189      /* Allocated in VFP registers. */
190      if(vi < ecif->cif->vfp_nargs && is_vfp_type)
191        {
192          char *vfp_slot = (char *)(vfp_space + ecif->cif->vfp_args[vi++]);
193          ffi_put_arg(p_arg, p_argv, vfp_slot);
194          continue;
195        }
196      /* Try allocating in core registers. */
197      else if (!done_with_regs && !is_vfp_type)
198        {
199          char *tregp = ffi_align(p_arg, regp);
200          size_t size = (*p_arg)->size;
201          size = (size < 4)? 4 : size; // pad
202          /* Check if there is space left in the aligned register area to place
203           * the argument */
204          if(tregp + size <= eo_regp)
205            {
206              regp = tregp + ffi_put_arg(p_arg, p_argv, tregp);
207              done_with_regs = (regp == argp);
208              // ensure we did not write into the stack area
209              FFI_ASSERT(regp <= argp);
210              continue;
211            }
212          /* In case there are no arguments in the stack area yet,
213          the argument is passed in the remaining core registers and on the
214          stack. */
215          else if (!stack_used)
216            {
217              stack_used = 1;
218              done_with_regs = 1;
219              argp = tregp + ffi_put_arg(p_arg, p_argv, tregp);
220              FFI_ASSERT(eo_regp < argp);
221              continue;
222            }
223        }
224      /* Base case, arguments are passed on the stack */
225      stack_used = 1;
226      argp = ffi_align(p_arg, argp);
227      argp += ffi_put_arg(p_arg, p_argv, argp);
228    }
229  /* Indicate the VFP registers used. */
230  return ecif->cif->vfp_used;
231}
232
233/* Perform machine dependent cif processing */
234ffi_status ffi_prep_cif_machdep(ffi_cif *cif)
235{
236  int type_code;
237  /* Round the stack up to a multiple of 8 bytes.  This isn't needed
238     everywhere, but it is on some platforms, and it doesn't harm anything
239     when it isn't needed.  */
240  cif->bytes = (cif->bytes + 7) & ~7;
241
242  /* Set the return type flag */
243  switch (cif->rtype->type)
244    {
245    case FFI_TYPE_VOID:
246    case FFI_TYPE_FLOAT:
247    case FFI_TYPE_DOUBLE:
248      cif->flags = (unsigned) cif->rtype->type;
249      break;
250
251    case FFI_TYPE_SINT64:
252    case FFI_TYPE_UINT64:
253      cif->flags = (unsigned) FFI_TYPE_SINT64;
254      break;
255
256    case FFI_TYPE_STRUCT:
257      if (cif->abi == FFI_VFP
258	  && (type_code = vfp_type_p (cif->rtype)) != 0)
259	{
260	  /* A Composite Type passed in VFP registers, either
261	     FFI_TYPE_STRUCT_VFP_FLOAT or FFI_TYPE_STRUCT_VFP_DOUBLE. */
262	  cif->flags = (unsigned) type_code;
263	}
264      else if (cif->rtype->size <= 4)
265	/* A Composite Type not larger than 4 bytes is returned in r0.  */
266	cif->flags = (unsigned)FFI_TYPE_INT;
267      else
268	/* A Composite Type larger than 4 bytes, or whose size cannot
269	   be determined statically ... is stored in memory at an
270	   address passed [in r0].  */
271	cif->flags = (unsigned)FFI_TYPE_STRUCT;
272      break;
273
274    default:
275      cif->flags = FFI_TYPE_INT;
276      break;
277    }
278
279  /* Map out the register placements of VFP register args.
280     The VFP hard-float calling conventions are slightly more sophisticated than
281     the base calling conventions, so we do it here instead of in ffi_prep_args(). */
282  if (cif->abi == FFI_VFP)
283    layout_vfp_args (cif);
284
285  return FFI_OK;
286}
287
288/* Perform machine dependent cif processing for variadic calls */
289ffi_status ffi_prep_cif_machdep_var(ffi_cif *cif,
290				    unsigned int nfixedargs,
291				    unsigned int ntotalargs)
292{
293  /* VFP variadic calls actually use the SYSV ABI */
294  if (cif->abi == FFI_VFP)
295	cif->abi = FFI_SYSV;
296
297  return ffi_prep_cif_machdep(cif);
298}
299
300/* Prototypes for assembly functions, in sysv.S */
301extern void ffi_call_SYSV (void (*fn)(void), extended_cif *, unsigned, unsigned, unsigned *);
302extern void ffi_call_VFP (void (*fn)(void), extended_cif *, unsigned, unsigned, unsigned *);
303
304void ffi_call(ffi_cif *cif, void (*fn)(void), void *rvalue, void **avalue)
305{
306  extended_cif ecif;
307
308  int small_struct = (cif->flags == FFI_TYPE_INT
309		      && cif->rtype->type == FFI_TYPE_STRUCT);
310  int vfp_struct = (cif->flags == FFI_TYPE_STRUCT_VFP_FLOAT
311		    || cif->flags == FFI_TYPE_STRUCT_VFP_DOUBLE);
312
313  unsigned int temp;
314
315  ecif.cif = cif;
316  ecif.avalue = avalue;
317
318  /* If the return value is a struct and we don't have a return	*/
319  /* value address then we need to make one			*/
320
321  if ((rvalue == NULL) &&
322      (cif->flags == FFI_TYPE_STRUCT))
323    {
324      ecif.rvalue = alloca(cif->rtype->size);
325    }
326  else if (small_struct)
327    ecif.rvalue = &temp;
328  else if (vfp_struct)
329    {
330      /* Largest case is double x 4. */
331      ecif.rvalue = alloca(32);
332    }
333  else
334    ecif.rvalue = rvalue;
335
336  switch (cif->abi)
337    {
338    case FFI_SYSV:
339      ffi_call_SYSV (fn, &ecif, cif->bytes, cif->flags, ecif.rvalue);
340      break;
341
342    case FFI_VFP:
343#ifdef __ARM_EABI__
344      ffi_call_VFP (fn, &ecif, cif->bytes, cif->flags, ecif.rvalue);
345      break;
346#endif
347
348    default:
349      FFI_ASSERT(0);
350      break;
351    }
352  if (small_struct)
353    {
354      FFI_ASSERT(rvalue != NULL);
355      memcpy (rvalue, &temp, cif->rtype->size);
356    }
357
358  else if (vfp_struct)
359    {
360      FFI_ASSERT(rvalue != NULL);
361      memcpy (rvalue, ecif.rvalue, cif->rtype->size);
362    }
363
364}
365
366/** private members **/
367
368static void ffi_prep_incoming_args_SYSV (char *stack, void **ret,
369					 void** args, ffi_cif* cif, float *vfp_stack);
370
371static void ffi_prep_incoming_args_VFP (char *stack, void **ret,
372					 void** args, ffi_cif* cif, float *vfp_stack);
373
374void ffi_closure_SYSV (ffi_closure *);
375
376void ffi_closure_VFP (ffi_closure *);
377
378/* This function is jumped to by the trampoline */
379
380unsigned int FFI_HIDDEN
381ffi_closure_inner (ffi_closure *closure,
382		   void **respp, void *args, void *vfp_args)
383{
384  // our various things...
385  ffi_cif       *cif;
386  void         **arg_area;
387
388  cif         = closure->cif;
389  arg_area    = (void**) alloca (cif->nargs * sizeof (void*));
390
391  /* this call will initialize ARG_AREA, such that each
392   * element in that array points to the corresponding
393   * value on the stack; and if the function returns
394   * a structure, it will re-set RESP to point to the
395   * structure return address.  */
396  if (cif->abi == FFI_VFP)
397    ffi_prep_incoming_args_VFP(args, respp, arg_area, cif, vfp_args);
398  else
399    ffi_prep_incoming_args_SYSV(args, respp, arg_area, cif, vfp_args);
400
401  (closure->fun) (cif, *respp, arg_area, closure->user_data);
402
403  return cif->flags;
404}
405
406/*@-exportheader@*/
407static void
408ffi_prep_incoming_args_SYSV(char *stack, void **rvalue,
409			    void **avalue, ffi_cif *cif,
410			    /* Used only under VFP hard-float ABI. */
411			    float *vfp_stack)
412/*@=exportheader@*/
413{
414  register unsigned int i;
415  register void **p_argv;
416  register char *argp;
417  register ffi_type **p_arg;
418
419  argp = stack;
420
421  if ( cif->flags == FFI_TYPE_STRUCT ) {
422    *rvalue = *(void **) argp;
423    argp += 4;
424  }
425
426  p_argv = avalue;
427
428  for (i = cif->nargs, p_arg = cif->arg_types; (i != 0); i--, p_arg++)
429    {
430      size_t z;
431
432      argp = ffi_align(p_arg, argp);
433
434      z = (*p_arg)->size;
435
436      /* because we're little endian, this is what it turns into.   */
437
438      *p_argv = (void*) argp;
439
440      p_argv++;
441      argp += z;
442    }
443
444  return;
445}
446
447/*@-exportheader@*/
448static void
449ffi_prep_incoming_args_VFP(char *stack, void **rvalue,
450			    void **avalue, ffi_cif *cif,
451			    /* Used only under VFP hard-float ABI. */
452			    float *vfp_stack)
453/*@=exportheader@*/
454{
455  register unsigned int i, vi = 0;
456  register void **p_argv;
457  register char *argp, *regp, *eo_regp;
458  register ffi_type **p_arg;
459  char done_with_regs = 0;
460  char stack_used = 0;
461  char is_vfp_type;
462
463  FFI_ASSERT(cif->abi == FFI_VFP);
464  regp = stack;
465  eo_regp = argp = regp + 16;
466
467  if ( cif->flags == FFI_TYPE_STRUCT ) {
468    *rvalue = *(void **) regp;
469    regp += 4;
470  }
471
472  p_argv = avalue;
473
474  for (i = cif->nargs, p_arg = cif->arg_types; (i != 0); i--, p_arg++)
475    {
476    size_t z;
477    is_vfp_type = vfp_type_p (*p_arg);
478
479    if(vi < cif->vfp_nargs && is_vfp_type)
480      {
481        *p_argv++ = (void*)(vfp_stack + cif->vfp_args[vi++]);
482        continue;
483      }
484    else if (!done_with_regs && !is_vfp_type)
485      {
486        char* tregp = ffi_align(p_arg, regp);
487
488        z = (*p_arg)->size;
489        z = (z < 4)? 4 : z; // pad
490
491        /* if the arguments either fits into the registers or uses registers
492         * and stack, while we haven't read other things from the stack */
493        if(tregp + z <= eo_regp || !stack_used)
494          {
495          /* because we're little endian, this is what it turns into. */
496          *p_argv = (void*) tregp;
497
498          p_argv++;
499          regp = tregp + z;
500          // if we read past the last core register, make sure we have not read
501          // from the stack before and continue reading after regp
502          if(regp > eo_regp)
503            {
504            if(stack_used)
505              {
506                abort(); // we should never read past the end of the register
507                         // are if the stack is already in use
508              }
509            argp = regp;
510            }
511          if(regp >= eo_regp)
512            {
513            done_with_regs = 1;
514            stack_used = 1;
515            }
516          continue;
517          }
518      }
519    stack_used = 1;
520
521    argp = ffi_align(p_arg, argp);
522
523    z = (*p_arg)->size;
524
525    /* because we're little endian, this is what it turns into.   */
526
527    *p_argv = (void*) argp;
528
529    p_argv++;
530    argp += z;
531    }
532
533  return;
534}
535
536/* How to make a trampoline.  */
537
538extern unsigned int ffi_arm_trampoline[3];
539
540#if FFI_EXEC_TRAMPOLINE_TABLE
541
542#include <mach/mach.h>
543#include <pthread.h>
544#include <stdio.h>
545#include <stdlib.h>
546
547extern void *ffi_closure_trampoline_table_page;
548
549typedef struct ffi_trampoline_table ffi_trampoline_table;
550typedef struct ffi_trampoline_table_entry ffi_trampoline_table_entry;
551
552struct ffi_trampoline_table {
553  /* contiguous writable and executable pages */
554  vm_address_t config_page;
555  vm_address_t trampoline_page;
556
557  /* free list tracking */
558  uint16_t free_count;
559  ffi_trampoline_table_entry *free_list;
560  ffi_trampoline_table_entry *free_list_pool;
561
562  ffi_trampoline_table *prev;
563  ffi_trampoline_table *next;
564};
565
566struct ffi_trampoline_table_entry {
567  void *(*trampoline)();
568  ffi_trampoline_table_entry *next;
569};
570
571/* Override the standard architecture trampoline size */
572// XXX TODO - Fix
573#undef FFI_TRAMPOLINE_SIZE
574#define FFI_TRAMPOLINE_SIZE 12
575
576/* The trampoline configuration is placed at 4080 bytes prior to the trampoline's entry point */
577#define FFI_TRAMPOLINE_CODELOC_CONFIG(codeloc) ((void **) (((uint8_t *) codeloc) - 4080));
578
579/* The first 16 bytes of the config page are unused, as they are unaddressable from the trampoline page. */
580#define FFI_TRAMPOLINE_CONFIG_PAGE_OFFSET 16
581
582/* Total number of trampolines that fit in one trampoline table */
583#define FFI_TRAMPOLINE_COUNT ((PAGE_SIZE - FFI_TRAMPOLINE_CONFIG_PAGE_OFFSET) / FFI_TRAMPOLINE_SIZE)
584
585static pthread_mutex_t ffi_trampoline_lock = PTHREAD_MUTEX_INITIALIZER;
586static ffi_trampoline_table *ffi_trampoline_tables = NULL;
587
588static ffi_trampoline_table *
589ffi_trampoline_table_alloc ()
590{
591  ffi_trampoline_table *table = NULL;
592
593  /* Loop until we can allocate two contiguous pages */
594  while (table == NULL) {
595    vm_address_t config_page = 0x0;
596    kern_return_t kt;
597
598    /* Try to allocate two pages */
599    kt = vm_allocate (mach_task_self (), &config_page, PAGE_SIZE*2, VM_FLAGS_ANYWHERE);
600    if (kt != KERN_SUCCESS) {
601      fprintf(stderr, "vm_allocate() failure: %d at %s:%d\n", kt, __FILE__, __LINE__);
602      break;
603    }
604
605    /* Now drop the second half of the allocation to make room for the trampoline table */
606    vm_address_t trampoline_page = config_page+PAGE_SIZE;
607    kt = vm_deallocate (mach_task_self (), trampoline_page, PAGE_SIZE);
608    if (kt != KERN_SUCCESS) {
609      fprintf(stderr, "vm_deallocate() failure: %d at %s:%d\n", kt, __FILE__, __LINE__);
610      break;
611    }
612
613    /* Remap the trampoline table to directly follow the config page */
614    vm_prot_t cur_prot;
615    vm_prot_t max_prot;
616
617    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);
618
619    /* If we lost access to the destination trampoline page, drop our config allocation mapping and retry */
620    if (kt != KERN_SUCCESS) {
621      /* Log unexpected failures */
622      if (kt != KERN_NO_SPACE) {
623        fprintf(stderr, "vm_remap() failure: %d at %s:%d\n", kt, __FILE__, __LINE__);
624      }
625
626      vm_deallocate (mach_task_self (), config_page, PAGE_SIZE);
627      continue;
628    }
629
630    /* We have valid trampoline and config pages */
631    table = calloc (1, sizeof(ffi_trampoline_table));
632    table->free_count = FFI_TRAMPOLINE_COUNT;
633    table->config_page = config_page;
634    table->trampoline_page = trampoline_page;
635
636    /* Create and initialize the free list */
637    table->free_list_pool = calloc(FFI_TRAMPOLINE_COUNT, sizeof(ffi_trampoline_table_entry));
638
639    uint16_t i;
640    for (i = 0; i < table->free_count; i++) {
641      ffi_trampoline_table_entry *entry = &table->free_list_pool[i];
642      entry->trampoline = (void *) (table->trampoline_page + (i * FFI_TRAMPOLINE_SIZE));
643
644      if (i < table->free_count - 1)
645        entry->next = &table->free_list_pool[i+1];
646    }
647
648    table->free_list = table->free_list_pool;
649  }
650
651  return table;
652}
653
654void *
655ffi_closure_alloc (size_t size, void **code)
656{
657  /* Create the closure */
658  ffi_closure *closure = malloc(size);
659  if (closure == NULL)
660    return NULL;
661
662  pthread_mutex_lock(&ffi_trampoline_lock);
663
664  /* Check for an active trampoline table with available entries. */
665  ffi_trampoline_table *table = ffi_trampoline_tables;
666  if (table == NULL || table->free_list == NULL) {
667    table = ffi_trampoline_table_alloc ();
668    if (table == NULL) {
669      free(closure);
670      return NULL;
671    }
672
673    /* Insert the new table at the top of the list */
674    table->next = ffi_trampoline_tables;
675    if (table->next != NULL)
676        table->next->prev = table;
677
678    ffi_trampoline_tables = table;
679  }
680
681  /* Claim the free entry */
682  ffi_trampoline_table_entry *entry = ffi_trampoline_tables->free_list;
683  ffi_trampoline_tables->free_list = entry->next;
684  ffi_trampoline_tables->free_count--;
685  entry->next = NULL;
686
687  pthread_mutex_unlock(&ffi_trampoline_lock);
688
689  /* Initialize the return values */
690  *code = entry->trampoline;
691  closure->trampoline_table = table;
692  closure->trampoline_table_entry = entry;
693
694  return closure;
695}
696
697void
698ffi_closure_free (void *ptr)
699{
700  ffi_closure *closure = ptr;
701
702  pthread_mutex_lock(&ffi_trampoline_lock);
703
704  /* Fetch the table and entry references */
705  ffi_trampoline_table *table = closure->trampoline_table;
706  ffi_trampoline_table_entry *entry = closure->trampoline_table_entry;
707
708  /* Return the entry to the free list */
709  entry->next = table->free_list;
710  table->free_list = entry;
711  table->free_count++;
712
713  /* If all trampolines within this table are free, and at least one other table exists, deallocate
714   * the table */
715  if (table->free_count == FFI_TRAMPOLINE_COUNT && ffi_trampoline_tables != table) {
716    /* Remove from the list */
717    if (table->prev != NULL)
718      table->prev->next = table->next;
719
720    if (table->next != NULL)
721      table->next->prev = table->prev;
722
723    /* Deallocate pages */
724    kern_return_t kt;
725    kt = vm_deallocate (mach_task_self (), table->config_page, PAGE_SIZE);
726    if (kt != KERN_SUCCESS)
727      fprintf(stderr, "vm_deallocate() failure: %d at %s:%d\n", kt, __FILE__, __LINE__);
728
729    kt = vm_deallocate (mach_task_self (), table->trampoline_page, PAGE_SIZE);
730    if (kt != KERN_SUCCESS)
731      fprintf(stderr, "vm_deallocate() failure: %d at %s:%d\n", kt, __FILE__, __LINE__);
732
733    /* Deallocate free list */
734    free (table->free_list_pool);
735    free (table);
736  } else if (ffi_trampoline_tables != table) {
737    /* Otherwise, bump this table to the top of the list */
738    table->prev = NULL;
739    table->next = ffi_trampoline_tables;
740    if (ffi_trampoline_tables != NULL)
741      ffi_trampoline_tables->prev = table;
742
743    ffi_trampoline_tables = table;
744  }
745
746  pthread_mutex_unlock (&ffi_trampoline_lock);
747
748  /* Free the closure */
749  free (closure);
750}
751
752#else
753
754#define FFI_INIT_TRAMPOLINE(TRAMP,FUN,CTX)				\
755({ unsigned char *__tramp = (unsigned char*)(TRAMP);			\
756   unsigned int  __fun = (unsigned int)(FUN);				\
757   unsigned int  __ctx = (unsigned int)(CTX);				\
758   unsigned char *insns = (unsigned char *)(CTX);                       \
759   memcpy (__tramp, ffi_arm_trampoline, sizeof ffi_arm_trampoline);     \
760   *(unsigned int*) &__tramp[12] = __ctx;				\
761   *(unsigned int*) &__tramp[16] = __fun;				\
762   __clear_cache((&__tramp[0]), (&__tramp[19])); /* Clear data mapping.  */ \
763   __clear_cache(insns, insns + 3 * sizeof (unsigned int));             \
764                                                 /* Clear instruction   \
765                                                    mapping.  */        \
766 })
767
768#endif
769
770/* the cif must already be prep'ed */
771
772ffi_status
773ffi_prep_closure_loc (ffi_closure* closure,
774		      ffi_cif* cif,
775		      void (*fun)(ffi_cif*,void*,void**,void*),
776		      void *user_data,
777		      void *codeloc)
778{
779  void (*closure_func)(ffi_closure*) = NULL;
780
781  if (cif->abi == FFI_SYSV)
782    closure_func = &ffi_closure_SYSV;
783#ifdef __ARM_EABI__
784  else if (cif->abi == FFI_VFP)
785    closure_func = &ffi_closure_VFP;
786#endif
787  else
788    return FFI_BAD_ABI;
789
790#if FFI_EXEC_TRAMPOLINE_TABLE
791  void **config = FFI_TRAMPOLINE_CODELOC_CONFIG(codeloc);
792  config[0] = closure;
793  config[1] = closure_func;
794#else
795  FFI_INIT_TRAMPOLINE (&closure->tramp[0], \
796		       closure_func,  \
797		       codeloc);
798#endif
799
800  closure->cif  = cif;
801  closure->user_data = user_data;
802  closure->fun  = fun;
803
804  return FFI_OK;
805}
806
807/* Below are routines for VFP hard-float support. */
808
809static int rec_vfp_type_p (ffi_type *t, int *elt, int *elnum)
810{
811  switch (t->type)
812    {
813    case FFI_TYPE_FLOAT:
814    case FFI_TYPE_DOUBLE:
815      *elt = (int) t->type;
816      *elnum = 1;
817      return 1;
818
819    case FFI_TYPE_STRUCT_VFP_FLOAT:
820      *elt = FFI_TYPE_FLOAT;
821      *elnum = t->size / sizeof (float);
822      return 1;
823
824    case FFI_TYPE_STRUCT_VFP_DOUBLE:
825      *elt = FFI_TYPE_DOUBLE;
826      *elnum = t->size / sizeof (double);
827      return 1;
828
829    case FFI_TYPE_STRUCT:;
830      {
831	int base_elt = 0, total_elnum = 0;
832	ffi_type **el = t->elements;
833	while (*el)
834	  {
835	    int el_elt = 0, el_elnum = 0;
836	    if (! rec_vfp_type_p (*el, &el_elt, &el_elnum)
837		|| (base_elt && base_elt != el_elt)
838		|| total_elnum + el_elnum > 4)
839	      return 0;
840	    base_elt = el_elt;
841	    total_elnum += el_elnum;
842	    el++;
843	  }
844	*elnum = total_elnum;
845	*elt = base_elt;
846	return 1;
847      }
848    default: ;
849    }
850  return 0;
851}
852
853static int vfp_type_p (ffi_type *t)
854{
855  int elt, elnum;
856  if (rec_vfp_type_p (t, &elt, &elnum))
857    {
858      if (t->type == FFI_TYPE_STRUCT)
859	{
860	  if (elnum == 1)
861	    t->type = elt;
862	  else
863	    t->type = (elt == FFI_TYPE_FLOAT
864		       ? FFI_TYPE_STRUCT_VFP_FLOAT
865		       : FFI_TYPE_STRUCT_VFP_DOUBLE);
866	}
867      return (int) t->type;
868    }
869  return 0;
870}
871
872static int place_vfp_arg (ffi_cif *cif, ffi_type *t)
873{
874  short reg = cif->vfp_reg_free;
875  int nregs = t->size / sizeof (float);
876  int align = ((t->type == FFI_TYPE_STRUCT_VFP_FLOAT
877		|| t->type == FFI_TYPE_FLOAT) ? 1 : 2);
878  /* Align register number. */
879  if ((reg & 1) && align == 2)
880    reg++;
881  while (reg + nregs <= 16)
882    {
883      int s, new_used = 0;
884      for (s = reg; s < reg + nregs; s++)
885	{
886	  new_used |= (1 << s);
887	  if (cif->vfp_used & (1 << s))
888	    {
889	      reg += align;
890	      goto next_reg;
891	    }
892	}
893      /* Found regs to allocate. */
894      cif->vfp_used |= new_used;
895      cif->vfp_args[cif->vfp_nargs++] = reg;
896
897      /* Update vfp_reg_free. */
898      if (cif->vfp_used & (1 << cif->vfp_reg_free))
899	{
900	  reg += nregs;
901	  while (cif->vfp_used & (1 << reg))
902	    reg += 1;
903	  cif->vfp_reg_free = reg;
904	}
905      return 0;
906    next_reg: ;
907    }
908  // done, mark all regs as used
909  cif->vfp_reg_free = 16;
910  cif->vfp_used = 0xFFFF;
911  return 1;
912}
913
914static void layout_vfp_args (ffi_cif *cif)
915{
916  int i;
917  /* Init VFP fields */
918  cif->vfp_used = 0;
919  cif->vfp_nargs = 0;
920  cif->vfp_reg_free = 0;
921  memset (cif->vfp_args, -1, 16); /* Init to -1. */
922
923  for (i = 0; i < cif->nargs; i++)
924    {
925      ffi_type *t = cif->arg_types[i];
926      if (vfp_type_p (t) && place_vfp_arg (cif, t) == 1)
927        {
928          break;
929        }
930    }
931}
932