2018-10-25 Richard Biener <rguenther@suse.de>
[official-gcc.git] / libffi / src / arm / ffi.c
blob9c8732d158cd1573544e095cd5e568e7c4a1e9f3
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.
8 ARM Foreign Function Interface
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:
18 The above copyright notice and this permission notice shall be included
19 in all copies or substantial portions of the Software.
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 ----------------------------------------------------------------------- */
31 #include <ffi.h>
32 #include <ffi_common.h>
33 #include <stdlib.h>
34 #include "internal.h"
36 /* Forward declares. */
37 static int vfp_type_p (const ffi_type *);
38 static void layout_vfp_args (ffi_cif *);
40 static void *
41 ffi_align (ffi_type *ty, void *p)
43 /* Align if necessary */
44 size_t alignment;
45 #ifdef _WIN32_WCE
46 alignment = 4;
47 #else
48 alignment = ty->alignment;
49 if (alignment < 4)
50 alignment = 4;
51 #endif
52 return (void *) ALIGN (p, alignment);
55 static size_t
56 ffi_put_arg (ffi_type *ty, void *src, void *dst)
58 size_t z = ty->size;
60 switch (ty->type)
62 case FFI_TYPE_SINT8:
63 *(UINT32 *)dst = *(SINT8 *)src;
64 break;
65 case FFI_TYPE_UINT8:
66 *(UINT32 *)dst = *(UINT8 *)src;
67 break;
68 case FFI_TYPE_SINT16:
69 *(UINT32 *)dst = *(SINT16 *)src;
70 break;
71 case FFI_TYPE_UINT16:
72 *(UINT32 *)dst = *(UINT16 *)src;
73 break;
75 case FFI_TYPE_INT:
76 case FFI_TYPE_SINT32:
77 case FFI_TYPE_UINT32:
78 case FFI_TYPE_POINTER:
79 case FFI_TYPE_FLOAT:
80 *(UINT32 *)dst = *(UINT32 *)src;
81 break;
83 case FFI_TYPE_SINT64:
84 case FFI_TYPE_UINT64:
85 case FFI_TYPE_DOUBLE:
86 *(UINT64 *)dst = *(UINT64 *)src;
87 break;
89 case FFI_TYPE_STRUCT:
90 case FFI_TYPE_COMPLEX:
91 memcpy (dst, src, z);
92 break;
94 default:
95 abort();
98 return ALIGN (z, 4);
101 /* ffi_prep_args is called once stack space has been allocated
102 for the function's arguments.
104 The vfp_space parameter is the load area for VFP regs, the return
105 value is cif->vfp_used (word bitset of VFP regs used for passing
106 arguments). These are only used for the VFP hard-float ABI.
108 static void
109 ffi_prep_args_SYSV (ffi_cif *cif, int flags, void *rvalue,
110 void **avalue, char *argp)
112 ffi_type **arg_types = cif->arg_types;
113 int i, n;
115 if (flags == ARM_TYPE_STRUCT)
117 *(void **) argp = rvalue;
118 argp += 4;
121 for (i = 0, n = cif->nargs; i < n; i++)
123 ffi_type *ty = arg_types[i];
124 argp = ffi_align (ty, argp);
125 argp += ffi_put_arg (ty, avalue[i], argp);
129 static void
130 ffi_prep_args_VFP (ffi_cif *cif, int flags, void *rvalue,
131 void **avalue, char *stack, char *vfp_space)
133 ffi_type **arg_types = cif->arg_types;
134 int i, n, vi = 0;
135 char *argp, *regp, *eo_regp;
136 char stack_used = 0;
137 char done_with_regs = 0;
139 /* The first 4 words on the stack are used for values
140 passed in core registers. */
141 regp = stack;
142 eo_regp = argp = regp + 16;
144 /* If the function returns an FFI_TYPE_STRUCT in memory,
145 that address is passed in r0 to the function. */
146 if (flags == ARM_TYPE_STRUCT)
148 *(void **) regp = rvalue;
149 regp += 4;
152 for (i = 0, n = cif->nargs; i < n; i++)
154 ffi_type *ty = arg_types[i];
155 void *a = avalue[i];
156 int is_vfp_type = vfp_type_p (ty);
158 /* Allocated in VFP registers. */
159 if (vi < cif->vfp_nargs && is_vfp_type)
161 char *vfp_slot = vfp_space + cif->vfp_args[vi++] * 4;
162 ffi_put_arg (ty, a, vfp_slot);
163 continue;
165 /* Try allocating in core registers. */
166 else if (!done_with_regs && !is_vfp_type)
168 char *tregp = ffi_align (ty, regp);
169 size_t size = ty->size;
170 size = (size < 4) ? 4 : size; // pad
171 /* Check if there is space left in the aligned register
172 area to place the argument. */
173 if (tregp + size <= eo_regp)
175 regp = tregp + ffi_put_arg (ty, a, tregp);
176 done_with_regs = (regp == argp);
177 // ensure we did not write into the stack area
178 FFI_ASSERT (regp <= argp);
179 continue;
181 /* In case there are no arguments in the stack area yet,
182 the argument is passed in the remaining core registers
183 and on the stack. */
184 else if (!stack_used)
186 stack_used = 1;
187 done_with_regs = 1;
188 argp = tregp + ffi_put_arg (ty, a, tregp);
189 FFI_ASSERT (eo_regp < argp);
190 continue;
193 /* Base case, arguments are passed on the stack */
194 stack_used = 1;
195 argp = ffi_align (ty, argp);
196 argp += ffi_put_arg (ty, a, argp);
200 /* Perform machine dependent cif processing */
201 ffi_status
202 ffi_prep_cif_machdep (ffi_cif *cif)
204 int flags = 0, cabi = cif->abi;
205 size_t bytes = cif->bytes;
207 /* Map out the register placements of VFP register args. The VFP
208 hard-float calling conventions are slightly more sophisticated
209 than the base calling conventions, so we do it here instead of
210 in ffi_prep_args(). */
211 if (cabi == FFI_VFP)
212 layout_vfp_args (cif);
214 /* Set the return type flag */
215 switch (cif->rtype->type)
217 case FFI_TYPE_VOID:
218 flags = ARM_TYPE_VOID;
219 break;
221 case FFI_TYPE_INT:
222 case FFI_TYPE_UINT8:
223 case FFI_TYPE_SINT8:
224 case FFI_TYPE_UINT16:
225 case FFI_TYPE_SINT16:
226 case FFI_TYPE_UINT32:
227 case FFI_TYPE_SINT32:
228 case FFI_TYPE_POINTER:
229 flags = ARM_TYPE_INT;
230 break;
232 case FFI_TYPE_SINT64:
233 case FFI_TYPE_UINT64:
234 flags = ARM_TYPE_INT64;
235 break;
237 case FFI_TYPE_FLOAT:
238 flags = (cabi == FFI_VFP ? ARM_TYPE_VFP_S : ARM_TYPE_INT);
239 break;
240 case FFI_TYPE_DOUBLE:
241 flags = (cabi == FFI_VFP ? ARM_TYPE_VFP_D : ARM_TYPE_INT64);
242 break;
244 case FFI_TYPE_STRUCT:
245 case FFI_TYPE_COMPLEX:
246 if (cabi == FFI_VFP)
248 int h = vfp_type_p (cif->rtype);
250 flags = ARM_TYPE_VFP_N;
251 if (h == 0x100 + FFI_TYPE_FLOAT)
252 flags = ARM_TYPE_VFP_S;
253 if (h == 0x100 + FFI_TYPE_DOUBLE)
254 flags = ARM_TYPE_VFP_D;
255 if (h != 0)
256 break;
259 /* A Composite Type not larger than 4 bytes is returned in r0.
260 A Composite Type larger than 4 bytes, or whose size cannot
261 be determined statically ... is stored in memory at an
262 address passed [in r0]. */
263 if (cif->rtype->size <= 4)
264 flags = ARM_TYPE_INT;
265 else
267 flags = ARM_TYPE_STRUCT;
268 bytes += 4;
270 break;
272 default:
273 abort();
276 /* Round the stack up to a multiple of 8 bytes. This isn't needed
277 everywhere, but it is on some platforms, and it doesn't harm anything
278 when it isn't needed. */
279 bytes = ALIGN (bytes, 8);
281 /* Minimum stack space is the 4 register arguments that we pop. */
282 if (bytes < 4*4)
283 bytes = 4*4;
285 cif->bytes = bytes;
286 cif->flags = flags;
288 return FFI_OK;
291 /* Perform machine dependent cif processing for variadic calls */
292 ffi_status
293 ffi_prep_cif_machdep_var (ffi_cif * cif,
294 unsigned int nfixedargs, unsigned int ntotalargs)
296 /* VFP variadic calls actually use the SYSV ABI */
297 if (cif->abi == FFI_VFP)
298 cif->abi = FFI_SYSV;
300 return ffi_prep_cif_machdep (cif);
303 /* Prototypes for assembly functions, in sysv.S. */
305 struct call_frame
307 void *fp;
308 void *lr;
309 void *rvalue;
310 int flags;
311 void *closure;
314 extern void ffi_call_SYSV (void *stack, struct call_frame *,
315 void (*fn) (void)) FFI_HIDDEN;
316 extern void ffi_call_VFP (void *vfp_space, struct call_frame *,
317 void (*fn) (void), unsigned vfp_used) FFI_HIDDEN;
319 static void
320 ffi_call_int (ffi_cif * cif, void (*fn) (void), void *rvalue,
321 void **avalue, void *closure)
323 int flags = cif->flags;
324 ffi_type *rtype = cif->rtype;
325 size_t bytes, rsize, vfp_size;
326 char *stack, *vfp_space, *new_rvalue;
327 struct call_frame *frame;
329 rsize = 0;
330 if (rvalue == NULL)
332 /* If the return value is a struct and we don't have a return
333 value address then we need to make one. Otherwise the return
334 value is in registers and we can ignore them. */
335 if (flags == ARM_TYPE_STRUCT)
336 rsize = rtype->size;
337 else
338 flags = ARM_TYPE_VOID;
340 else if (flags == ARM_TYPE_VFP_N)
342 /* Largest case is double x 4. */
343 rsize = 32;
345 else if (flags == ARM_TYPE_INT && rtype->type == FFI_TYPE_STRUCT)
346 rsize = 4;
348 /* Largest case. */
349 vfp_size = (cif->abi == FFI_VFP && cif->vfp_used ? 8*8: 0);
351 bytes = cif->bytes;
352 stack = alloca (vfp_size + bytes + sizeof(struct call_frame) + rsize);
354 vfp_space = NULL;
355 if (vfp_size)
357 vfp_space = stack;
358 stack += vfp_size;
361 frame = (struct call_frame *)(stack + bytes);
363 new_rvalue = rvalue;
364 if (rsize)
365 new_rvalue = (void *)(frame + 1);
367 frame->rvalue = new_rvalue;
368 frame->flags = flags;
369 frame->closure = closure;
371 if (vfp_space)
373 ffi_prep_args_VFP (cif, flags, new_rvalue, avalue, stack, vfp_space);
374 ffi_call_VFP (vfp_space, frame, fn, cif->vfp_used);
376 else
378 ffi_prep_args_SYSV (cif, flags, new_rvalue, avalue, stack);
379 ffi_call_SYSV (stack, frame, fn);
382 if (rvalue && rvalue != new_rvalue)
383 memcpy (rvalue, new_rvalue, rtype->size);
386 void
387 ffi_call (ffi_cif *cif, void (*fn) (void), void *rvalue, void **avalue)
389 ffi_call_int (cif, fn, rvalue, avalue, NULL);
392 void
393 ffi_call_go (ffi_cif *cif, void (*fn) (void), void *rvalue,
394 void **avalue, void *closure)
396 ffi_call_int (cif, fn, rvalue, avalue, closure);
399 static void *
400 ffi_prep_incoming_args_SYSV (ffi_cif *cif, void *rvalue,
401 char *argp, void **avalue)
403 ffi_type **arg_types = cif->arg_types;
404 int i, n;
406 if (cif->flags == ARM_TYPE_STRUCT)
408 rvalue = *(void **) argp;
409 argp += 4;
412 for (i = 0, n = cif->nargs; i < n; i++)
414 ffi_type *ty = arg_types[i];
415 size_t z = ty->size;
417 argp = ffi_align (ty, argp);
418 avalue[i] = (void *) argp;
419 argp += z;
422 return rvalue;
425 static void *
426 ffi_prep_incoming_args_VFP (ffi_cif *cif, void *rvalue, char *stack,
427 char *vfp_space, void **avalue)
429 ffi_type **arg_types = cif->arg_types;
430 int i, n, vi = 0;
431 char *argp, *regp, *eo_regp;
432 char done_with_regs = 0;
433 char stack_used = 0;
435 regp = stack;
436 eo_regp = argp = regp + 16;
438 if (cif->flags == ARM_TYPE_STRUCT)
440 rvalue = *(void **) regp;
441 regp += 4;
444 for (i = 0, n = cif->nargs; i < n; i++)
446 ffi_type *ty = arg_types[i];
447 int is_vfp_type = vfp_type_p (ty);
448 size_t z = ty->size;
450 if (vi < cif->vfp_nargs && is_vfp_type)
452 avalue[i] = vfp_space + cif->vfp_args[vi++] * 4;
453 continue;
455 else if (!done_with_regs && !is_vfp_type)
457 char *tregp = ffi_align (ty, regp);
459 z = (z < 4) ? 4 : z; // pad
461 /* If the arguments either fits into the registers or uses registers
462 and stack, while we haven't read other things from the stack */
463 if (tregp + z <= eo_regp || !stack_used)
465 /* Because we're little endian, this is what it turns into. */
466 avalue[i] = (void *) tregp;
467 regp = tregp + z;
469 /* If we read past the last core register, make sure we
470 have not read from the stack before and continue
471 reading after regp. */
472 if (regp > eo_regp)
474 FFI_ASSERT (!stack_used);
475 argp = regp;
477 if (regp >= eo_regp)
479 done_with_regs = 1;
480 stack_used = 1;
482 continue;
486 stack_used = 1;
487 argp = ffi_align (ty, argp);
488 avalue[i] = (void *) argp;
489 argp += z;
492 return rvalue;
495 struct closure_frame
497 char vfp_space[8*8] __attribute__((aligned(8)));
498 char result[8*4];
499 char argp[];
502 int FFI_HIDDEN
503 ffi_closure_inner_SYSV (ffi_cif *cif,
504 void (*fun) (ffi_cif *, void *, void **, void *),
505 void *user_data,
506 struct closure_frame *frame)
508 void **avalue = (void **) alloca (cif->nargs * sizeof (void *));
509 void *rvalue = ffi_prep_incoming_args_SYSV (cif, frame->result,
510 frame->argp, avalue);
511 fun (cif, rvalue, avalue, user_data);
512 return cif->flags;
515 int FFI_HIDDEN
516 ffi_closure_inner_VFP (ffi_cif *cif,
517 void (*fun) (ffi_cif *, void *, void **, void *),
518 void *user_data,
519 struct closure_frame *frame)
521 void **avalue = (void **) alloca (cif->nargs * sizeof (void *));
522 void *rvalue = ffi_prep_incoming_args_VFP (cif, frame->result, frame->argp,
523 frame->vfp_space, avalue);
524 fun (cif, rvalue, avalue, user_data);
525 return cif->flags;
528 void ffi_closure_SYSV (void) FFI_HIDDEN;
529 void ffi_closure_VFP (void) FFI_HIDDEN;
530 void ffi_go_closure_SYSV (void) FFI_HIDDEN;
531 void ffi_go_closure_VFP (void) FFI_HIDDEN;
533 #if FFI_EXEC_TRAMPOLINE_TABLE
535 #include <mach/mach.h>
536 #include <pthread.h>
537 #include <stdio.h>
538 #include <stdlib.h>
540 extern void *ffi_closure_trampoline_table_page;
542 typedef struct ffi_trampoline_table ffi_trampoline_table;
543 typedef struct ffi_trampoline_table_entry ffi_trampoline_table_entry;
545 struct ffi_trampoline_table
547 /* contiguous writable and executable pages */
548 vm_address_t config_page;
549 vm_address_t trampoline_page;
551 /* free list tracking */
552 uint16_t free_count;
553 ffi_trampoline_table_entry *free_list;
554 ffi_trampoline_table_entry *free_list_pool;
556 ffi_trampoline_table *prev;
557 ffi_trampoline_table *next;
560 struct ffi_trampoline_table_entry
562 void *(*trampoline) ();
563 ffi_trampoline_table_entry *next;
566 /* Override the standard architecture trampoline size */
567 // XXX TODO - Fix
568 #undef FFI_TRAMPOLINE_SIZE
569 #define FFI_TRAMPOLINE_SIZE 12
571 /* The trampoline configuration is placed at 4080 bytes prior to the trampoline's entry point */
572 #define FFI_TRAMPOLINE_CODELOC_CONFIG(codeloc) ((void **) (((uint8_t *) codeloc) - 4080));
574 /* The first 16 bytes of the config page are unused, as they are unaddressable from the trampoline page. */
575 #define FFI_TRAMPOLINE_CONFIG_PAGE_OFFSET 16
577 /* Total number of trampolines that fit in one trampoline table */
578 #define FFI_TRAMPOLINE_COUNT ((PAGE_SIZE - FFI_TRAMPOLINE_CONFIG_PAGE_OFFSET) / FFI_TRAMPOLINE_SIZE)
580 static pthread_mutex_t ffi_trampoline_lock = PTHREAD_MUTEX_INITIALIZER;
581 static ffi_trampoline_table *ffi_trampoline_tables = NULL;
583 static ffi_trampoline_table *
584 ffi_trampoline_table_alloc ()
586 ffi_trampoline_table *table = NULL;
588 /* Loop until we can allocate two contiguous pages */
589 while (table == NULL)
591 vm_address_t config_page = 0x0;
592 kern_return_t kt;
594 /* Try to allocate two pages */
595 kt =
596 vm_allocate (mach_task_self (), &config_page, PAGE_SIZE * 2,
597 VM_FLAGS_ANYWHERE);
598 if (kt != KERN_SUCCESS)
600 fprintf (stderr, "vm_allocate() failure: %d at %s:%d\n", kt,
601 __FILE__, __LINE__);
602 break;
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)
610 fprintf (stderr, "vm_deallocate() failure: %d at %s:%d\n", kt,
611 __FILE__, __LINE__);
612 break;
615 /* Remap the trampoline table to directly follow the config page */
616 vm_prot_t cur_prot;
617 vm_prot_t max_prot;
619 kt =
620 vm_remap (mach_task_self (), &trampoline_page, PAGE_SIZE, 0x0, FALSE,
621 mach_task_self (),
622 (vm_address_t) & ffi_closure_trampoline_table_page, FALSE,
623 &cur_prot, &max_prot, VM_INHERIT_SHARE);
625 /* If we lost access to the destination trampoline page, drop our config allocation mapping and retry */
626 if (kt != KERN_SUCCESS)
628 /* Log unexpected failures */
629 if (kt != KERN_NO_SPACE)
631 fprintf (stderr, "vm_remap() failure: %d at %s:%d\n", kt,
632 __FILE__, __LINE__);
635 vm_deallocate (mach_task_self (), config_page, PAGE_SIZE);
636 continue;
639 /* We have valid trampoline and config pages */
640 table = calloc (1, sizeof (ffi_trampoline_table));
641 table->free_count = FFI_TRAMPOLINE_COUNT;
642 table->config_page = config_page;
643 table->trampoline_page = trampoline_page;
645 /* Create and initialize the free list */
646 table->free_list_pool =
647 calloc (FFI_TRAMPOLINE_COUNT, sizeof (ffi_trampoline_table_entry));
649 uint16_t i;
650 for (i = 0; i < table->free_count; i++)
652 ffi_trampoline_table_entry *entry = &table->free_list_pool[i];
653 entry->trampoline =
654 (void *) (table->trampoline_page + (i * FFI_TRAMPOLINE_SIZE));
656 if (i < table->free_count - 1)
657 entry->next = &table->free_list_pool[i + 1];
660 table->free_list = table->free_list_pool;
663 return table;
666 void *
667 ffi_closure_alloc (size_t size, void **code)
669 /* Create the closure */
670 ffi_closure *closure = malloc (size);
671 if (closure == NULL)
672 return NULL;
674 pthread_mutex_lock (&ffi_trampoline_lock);
676 /* Check for an active trampoline table with available entries. */
677 ffi_trampoline_table *table = ffi_trampoline_tables;
678 if (table == NULL || table->free_list == NULL)
680 table = ffi_trampoline_table_alloc ();
681 if (table == NULL)
683 free (closure);
684 return NULL;
687 /* Insert the new table at the top of the list */
688 table->next = ffi_trampoline_tables;
689 if (table->next != NULL)
690 table->next->prev = table;
692 ffi_trampoline_tables = table;
695 /* Claim the free entry */
696 ffi_trampoline_table_entry *entry = ffi_trampoline_tables->free_list;
697 ffi_trampoline_tables->free_list = entry->next;
698 ffi_trampoline_tables->free_count--;
699 entry->next = NULL;
701 pthread_mutex_unlock (&ffi_trampoline_lock);
703 /* Initialize the return values */
704 *code = entry->trampoline;
705 closure->trampoline_table = table;
706 closure->trampoline_table_entry = entry;
708 return closure;
711 void
712 ffi_closure_free (void *ptr)
714 ffi_closure *closure = ptr;
716 pthread_mutex_lock (&ffi_trampoline_lock);
718 /* Fetch the table and entry references */
719 ffi_trampoline_table *table = closure->trampoline_table;
720 ffi_trampoline_table_entry *entry = closure->trampoline_table_entry;
722 /* Return the entry to the free list */
723 entry->next = table->free_list;
724 table->free_list = entry;
725 table->free_count++;
727 /* If all trampolines within this table are free, and at least one other table exists, deallocate
728 * the table */
729 if (table->free_count == FFI_TRAMPOLINE_COUNT
730 && ffi_trampoline_tables != table)
732 /* Remove from the list */
733 if (table->prev != NULL)
734 table->prev->next = table->next;
736 if (table->next != NULL)
737 table->next->prev = table->prev;
739 /* Deallocate pages */
740 kern_return_t kt;
741 kt = vm_deallocate (mach_task_self (), table->config_page, PAGE_SIZE);
742 if (kt != KERN_SUCCESS)
743 fprintf (stderr, "vm_deallocate() failure: %d at %s:%d\n", kt,
744 __FILE__, __LINE__);
746 kt =
747 vm_deallocate (mach_task_self (), table->trampoline_page, PAGE_SIZE);
748 if (kt != KERN_SUCCESS)
749 fprintf (stderr, "vm_deallocate() failure: %d at %s:%d\n", kt,
750 __FILE__, __LINE__);
752 /* Deallocate free list */
753 free (table->free_list_pool);
754 free (table);
756 else if (ffi_trampoline_tables != table)
758 /* Otherwise, bump this table to the top of the list */
759 table->prev = NULL;
760 table->next = ffi_trampoline_tables;
761 if (ffi_trampoline_tables != NULL)
762 ffi_trampoline_tables->prev = table;
764 ffi_trampoline_tables = table;
767 pthread_mutex_unlock (&ffi_trampoline_lock);
769 /* Free the closure */
770 free (closure);
773 #else
775 extern unsigned int ffi_arm_trampoline[2] FFI_HIDDEN;
777 #endif
779 /* the cif must already be prep'ed */
781 ffi_status
782 ffi_prep_closure_loc (ffi_closure * closure,
783 ffi_cif * cif,
784 void (*fun) (ffi_cif *, void *, void **, void *),
785 void *user_data, void *codeloc)
787 void (*closure_func) (void) = ffi_closure_SYSV;
789 if (cif->abi == FFI_VFP)
791 /* We only need take the vfp path if there are vfp arguments. */
792 if (cif->vfp_used)
793 closure_func = ffi_closure_VFP;
795 else if (cif->abi != FFI_SYSV)
796 return FFI_BAD_ABI;
798 #if FFI_EXEC_TRAMPOLINE_TABLE
799 void **config = FFI_TRAMPOLINE_CODELOC_CONFIG (codeloc);
800 config[0] = closure;
801 config[1] = closure_func;
802 #else
803 memcpy (closure->tramp, ffi_arm_trampoline, 8);
804 __clear_cache(closure->tramp, closure->tramp + 8); /* clear data map */
805 __clear_cache(codeloc, codeloc + 8); /* clear insn map */
806 *(void (**)(void))(closure->tramp + 8) = closure_func;
807 #endif
809 closure->cif = cif;
810 closure->fun = fun;
811 closure->user_data = user_data;
813 return FFI_OK;
816 ffi_status
817 ffi_prep_go_closure (ffi_go_closure *closure, ffi_cif *cif,
818 void (*fun) (ffi_cif *, void *, void **, void *))
820 void (*closure_func) (void) = ffi_go_closure_SYSV;
822 if (cif->abi == FFI_VFP)
824 /* We only need take the vfp path if there are vfp arguments. */
825 if (cif->vfp_used)
826 closure_func = ffi_go_closure_VFP;
828 else if (cif->abi != FFI_SYSV)
829 return FFI_BAD_ABI;
831 closure->tramp = closure_func;
832 closure->cif = cif;
833 closure->fun = fun;
835 return FFI_OK;
838 /* Below are routines for VFP hard-float support. */
840 /* A subroutine of vfp_type_p. Given a structure type, return the type code
841 of the first non-structure element. Recurse for structure elements.
842 Return -1 if the structure is in fact empty, i.e. no nested elements. */
844 static int
845 is_hfa0 (const ffi_type *ty)
847 ffi_type **elements = ty->elements;
848 int i, ret = -1;
850 if (elements != NULL)
851 for (i = 0; elements[i]; ++i)
853 ret = elements[i]->type;
854 if (ret == FFI_TYPE_STRUCT || ret == FFI_TYPE_COMPLEX)
856 ret = is_hfa0 (elements[i]);
857 if (ret < 0)
858 continue;
860 break;
863 return ret;
866 /* A subroutine of vfp_type_p. Given a structure type, return true if all
867 of the non-structure elements are the same as CANDIDATE. */
869 static int
870 is_hfa1 (const ffi_type *ty, int candidate)
872 ffi_type **elements = ty->elements;
873 int i;
875 if (elements != NULL)
876 for (i = 0; elements[i]; ++i)
878 int t = elements[i]->type;
879 if (t == FFI_TYPE_STRUCT || t == FFI_TYPE_COMPLEX)
881 if (!is_hfa1 (elements[i], candidate))
882 return 0;
884 else if (t != candidate)
885 return 0;
888 return 1;
891 /* Determine if TY is an homogenous floating point aggregate (HFA).
892 That is, a structure consisting of 1 to 4 members of all the same type,
893 where that type is a floating point scalar.
895 Returns non-zero iff TY is an HFA. The result is an encoded value where
896 bits 0-7 contain the type code, and bits 8-10 contain the element count. */
898 static int
899 vfp_type_p (const ffi_type *ty)
901 ffi_type **elements;
902 int candidate, i;
903 size_t size, ele_count;
905 /* Quickest tests first. */
906 candidate = ty->type;
907 switch (ty->type)
909 default:
910 return 0;
911 case FFI_TYPE_FLOAT:
912 case FFI_TYPE_DOUBLE:
913 ele_count = 1;
914 goto done;
915 case FFI_TYPE_COMPLEX:
916 candidate = ty->elements[0]->type;
917 if (candidate != FFI_TYPE_FLOAT && candidate != FFI_TYPE_DOUBLE)
918 return 0;
919 ele_count = 2;
920 goto done;
921 case FFI_TYPE_STRUCT:
922 break;
925 /* No HFA types are smaller than 4 bytes, or larger than 32 bytes. */
926 size = ty->size;
927 if (size < 4 || size > 32)
928 return 0;
930 /* Find the type of the first non-structure member. */
931 elements = ty->elements;
932 candidate = elements[0]->type;
933 if (candidate == FFI_TYPE_STRUCT || candidate == FFI_TYPE_COMPLEX)
935 for (i = 0; ; ++i)
937 candidate = is_hfa0 (elements[i]);
938 if (candidate >= 0)
939 break;
943 /* If the first member is not a floating point type, it's not an HFA.
944 Also quickly re-check the size of the structure. */
945 switch (candidate)
947 case FFI_TYPE_FLOAT:
948 ele_count = size / sizeof(float);
949 if (size != ele_count * sizeof(float))
950 return 0;
951 break;
952 case FFI_TYPE_DOUBLE:
953 ele_count = size / sizeof(double);
954 if (size != ele_count * sizeof(double))
955 return 0;
956 break;
957 default:
958 return 0;
960 if (ele_count > 4)
961 return 0;
963 /* Finally, make sure that all scalar elements are the same type. */
964 for (i = 0; elements[i]; ++i)
966 int t = elements[i]->type;
967 if (t == FFI_TYPE_STRUCT || t == FFI_TYPE_COMPLEX)
969 if (!is_hfa1 (elements[i], candidate))
970 return 0;
972 else if (t != candidate)
973 return 0;
976 /* All tests succeeded. Encode the result. */
977 done:
978 return (ele_count << 8) | candidate;
981 static int
982 place_vfp_arg (ffi_cif *cif, int h)
984 unsigned short reg = cif->vfp_reg_free;
985 int align = 1, nregs = h >> 8;
987 if ((h & 0xff) == FFI_TYPE_DOUBLE)
988 align = 2, nregs *= 2;
990 /* Align register number. */
991 if ((reg & 1) && align == 2)
992 reg++;
994 while (reg + nregs <= 16)
996 int s, new_used = 0;
997 for (s = reg; s < reg + nregs; s++)
999 new_used |= (1 << s);
1000 if (cif->vfp_used & (1 << s))
1002 reg += align;
1003 goto next_reg;
1006 /* Found regs to allocate. */
1007 cif->vfp_used |= new_used;
1008 cif->vfp_args[cif->vfp_nargs++] = reg;
1010 /* Update vfp_reg_free. */
1011 if (cif->vfp_used & (1 << cif->vfp_reg_free))
1013 reg += nregs;
1014 while (cif->vfp_used & (1 << reg))
1015 reg += 1;
1016 cif->vfp_reg_free = reg;
1018 return 0;
1019 next_reg:;
1021 // done, mark all regs as used
1022 cif->vfp_reg_free = 16;
1023 cif->vfp_used = 0xFFFF;
1024 return 1;
1027 static void
1028 layout_vfp_args (ffi_cif * cif)
1030 int i;
1031 /* Init VFP fields */
1032 cif->vfp_used = 0;
1033 cif->vfp_nargs = 0;
1034 cif->vfp_reg_free = 0;
1035 memset (cif->vfp_args, -1, 16); /* Init to -1. */
1037 for (i = 0; i < cif->nargs; i++)
1039 int h = vfp_type_p (cif->arg_types[i]);
1040 if (h && place_vfp_arg (cif, h) == 1)
1041 break;