Ruby  2.7.2p137(2020-10-01revision5445e0435260b449decf2ac16f9d09bae3cafe72)
ffi.c
Go to the documentation of this file.
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. */
37 static int vfp_type_p (ffi_type *);
38 static void layout_vfp_args (ffi_cif *);
39 
40 int ffi_prep_args_SYSV(char *stack, extended_cif *ecif, float *vfp_space);
41 int ffi_prep_args_VFP(char *stack, extended_cif *ecif, float *vfp_space);
42 
43 static 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 
69 static 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 */
128 int 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 
155 int 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 */
234 ffi_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 */
289 ffi_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 */
301 extern void ffi_call_SYSV (void (*fn)(void), extended_cif *, unsigned, unsigned, unsigned *);
302 extern void ffi_call_VFP (void (*fn)(void), extended_cif *, unsigned, unsigned, unsigned *);
303 
304 void 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 
368 static void ffi_prep_incoming_args_SYSV (char *stack, void **ret,
369  void** args, ffi_cif* cif, float *vfp_stack);
370 
371 static void ffi_prep_incoming_args_VFP (char *stack, void **ret,
372  void** args, ffi_cif* cif, float *vfp_stack);
373 
374 void ffi_closure_SYSV (ffi_closure *);
375 
376 void ffi_closure_VFP (ffi_closure *);
377 
378 /* This function is jumped to by the trampoline */
379 
380 unsigned int FFI_HIDDEN
381 ffi_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@*/
407 static void
408 ffi_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@*/
448 static void
449 ffi_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 
538 extern 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 
547 extern void *ffi_closure_trampoline_table_page;
548 
549 typedef struct ffi_trampoline_table ffi_trampoline_table;
550 typedef struct ffi_trampoline_table_entry ffi_trampoline_table_entry;
551 
552 struct 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 
566 struct 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 
585 static pthread_mutex_t ffi_trampoline_lock = PTHREAD_MUTEX_INITIALIZER;
586 static ffi_trampoline_table *ffi_trampoline_tables = NULL;
587 
588 static ffi_trampoline_table *
589 ffi_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 
654 void *
655 ffi_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 
697 void
698 ffi_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 
772 ffi_status
773 ffi_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 
809 static 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 
820  *elt = FFI_TYPE_FLOAT;
821  *elnum = t->size / sizeof (float);
822  return 1;
823 
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 
853 static 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
866  }
867  return (int) t->type;
868  }
869  return 0;
870 }
871 
872 static 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 
914 static 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 }
memset
void * memset(void *, int, size_t)
abort
void abort(void) __attribute__((__noreturn__))
FFI_ASSERT
#define FFI_ASSERT(x)
Definition: ffi_common.h:72
ffi_prep_args_SYSV
int ffi_prep_args_SYSV(char *stack, extended_cif *ecif, float *vfp_space)
Definition: ffi.c:128
ffi_call_SYSV
void ffi_call_SYSV(unsigned(*)(struct call_context *context, unsigned char *, extended_cif *), struct call_context *context, extended_cif *, size_t, void(*fn)(void))
extended_cif::rvalue
void * rvalue
Definition: ffi_common.h:89
int
__inline__ int
Definition: rb_mjit_min_header-2.7.2.h:2877
i
uint32_t i
Definition: rb_mjit_min_header-2.7.2.h:5499
ffi_common.h
FFI_HIDDEN
const UINT64 ffi_template_tramp_tile[] FFI_HIDDEN
FFI_TRAMPOLINE_SIZE
#define FFI_TRAMPOLINE_SIZE
Definition: ffitarget.h:45
unsigned
#define unsigned
Definition: rb_mjit_min_header-2.7.2.h:2915
alloca
#define alloca(size)
Definition: rb_mjit_min_header-2.7.2.h:2525
FFI_VFP
@ FFI_VFP
Definition: ffitarget.h:44
FFI_TYPE_STRUCT_VFP_DOUBLE
#define FFI_TYPE_STRUCT_VFP_DOUBLE
Definition: ffitarget.h:61
FFI_SYSV
@ FFI_SYSV
Definition: ffitarget.h:36
ptr
struct RIMemo * ptr
Definition: debug.c:65
FFI_INIT_TRAMPOLINE
#define FFI_INIT_TRAMPOLINE(TRAMP, FUN, CTX)
Definition: ffi.c:754
ALIGN
#define ALIGN(v, a)
Definition: ffi_common.h:77
NULL
#define NULL
Definition: _sdbm.c:101
ffi_call_VFP
void ffi_call_VFP(void(*fn)(void), extended_cif *, unsigned, unsigned, unsigned *)
void
void
Definition: rb_mjit_min_header-2.7.2.h:13321
__pthread_mutex_t
Definition: rb_mjit_min_header-2.7.2.h:1383
PAGE_SIZE
#define PAGE_SIZE
Definition: rb_mjit_min_header-2.7.2.h:4136
ffi_prep_args_VFP
int ffi_prep_args_VFP(char *stack, extended_cif *ecif, float *vfp_space)
Definition: ffi.c:155
size
int size
Definition: encoding.c:58
FALSE
#define FALSE
Definition: nkf.h:174
ffi_prep_cif_machdep
ffi_status ffi_prep_cif_machdep(ffi_cif *cif)
Definition: ffi.c:758
arg
VALUE arg
Definition: rb_mjit_min_header-2.7.2.h:5636
ffi_closure_inner
unsigned int FFI_HIDDEN ffi_closure_inner(ffi_closure *closure, void **respp, void *args, void *vfp_args)
Definition: ffi.c:381
ffi_closure_VFP
void ffi_closure_VFP(ffi_closure *)
extended_cif
Definition: ffi_common.h:87
ffi_closure_SYSV
void ffi_closure_SYSV(ffi_closure *)
Definition: ffi.c:420
extended_cif::avalue
void ** avalue
Definition: ffi_common.h:90
memcpy
void * memcpy(void *__restrict, const void *__restrict, size_t)
FFI_TYPE_STRUCT_VFP_FLOAT
#define FFI_TYPE_STRUCT_VFP_FLOAT
Definition: ffitarget.h:60
pthread_mutex_lock
int pthread_mutex_lock(pthread_mutex_t *)
pthread_mutex_unlock
int pthread_mutex_unlock(pthread_mutex_t *)
free
#define free(x)
Definition: dln.c:52
ffi_call
void ffi_call(ffi_cif *cif, void(*fn)(void), void *rvalue, void **avalue)
Definition: ffi.c:813
stderr
#define stderr
Definition: rb_mjit_min_header-2.7.2.h:1522
ffi_prep_closure_loc
ffi_status ffi_prep_closure_loc(ffi_closure *closure, ffi_cif *cif, void(*fun)(ffi_cif *, void *, void **, void *), void *user_data, void *codeloc)
Definition: ffi.c:928
malloc
void * malloc(size_t) __attribute__((__malloc__)) __attribute__((__warn_unused_result__)) __attribute__((__alloc_size__(1)))
ffi_arm_trampoline
unsigned int ffi_arm_trampoline[3]
uint16_t
__uint16_t uint16_t
Definition: rb_mjit_min_header-2.7.2.h:1176
PTHREAD_MUTEX_INITIALIZER
#define PTHREAD_MUTEX_INITIALIZER
Definition: rb_mjit_min_header-2.7.2.h:9260
calloc
void * calloc(size_t, size_t) __attribute__((__malloc__)) __attribute__((__warn_unused_result__)) __attribute__((__alloc_size__(1
extended_cif::cif
ffi_cif * cif
Definition: ffi_common.h:88
double
double
Definition: rb_mjit_min_header-2.7.2.h:5958
fprintf
int fprintf(FILE *__restrict, const char *__restrict,...) __attribute__((__format__(__printf__
ffi_prep_cif_machdep_var
ffi_status ffi_prep_cif_machdep_var(ffi_cif *cif, unsigned int nfixedargs, unsigned int ntotalargs)
Definition: ffi.c:289