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 ----------------------------------------------------------------------- */
32 #include <ffi_common.h>
36 /* Forward declares. */
37 static int vfp_type_p (const ffi_type
*);
38 static void layout_vfp_args (ffi_cif
*);
41 ffi_align (ffi_type
*ty
, void *p
)
43 /* Align if necessary */
48 alignment
= ty
->alignment
;
52 return (void *) ALIGN (p
, alignment
);
56 ffi_put_arg (ffi_type
*ty
, void *src
, void *dst
)
63 *(UINT32
*)dst
= *(SINT8
*)src
;
66 *(UINT32
*)dst
= *(UINT8
*)src
;
69 *(UINT32
*)dst
= *(SINT16
*)src
;
72 *(UINT32
*)dst
= *(UINT16
*)src
;
78 case FFI_TYPE_POINTER
:
80 *(UINT32
*)dst
= *(UINT32
*)src
;
86 *(UINT64
*)dst
= *(UINT64
*)src
;
90 case FFI_TYPE_COMPLEX
:
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.
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
;
115 if (flags
== ARM_TYPE_STRUCT
)
117 *(void **) argp
= rvalue
;
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
);
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
;
135 char *argp
, *regp
, *eo_regp
;
137 char done_with_regs
= 0;
139 /* The first 4 words on the stack are used for values
140 passed in core registers. */
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
;
152 for (i
= 0, n
= cif
->nargs
; i
< n
; i
++)
154 ffi_type
*ty
= arg_types
[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
);
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
);
181 /* In case there are no arguments in the stack area yet,
182 the argument is passed in the remaining core registers
184 else if (!stack_used
)
188 argp
= tregp
+ ffi_put_arg (ty
, a
, tregp
);
189 FFI_ASSERT (eo_regp
< argp
);
193 /* Base case, arguments are passed on the stack */
195 argp
= ffi_align (ty
, argp
);
196 argp
+= ffi_put_arg (ty
, a
, argp
);
200 /* Perform machine dependent cif processing */
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(). */
212 layout_vfp_args (cif
);
214 /* Set the return type flag */
215 switch (cif
->rtype
->type
)
218 flags
= ARM_TYPE_VOID
;
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
;
232 case FFI_TYPE_SINT64
:
233 case FFI_TYPE_UINT64
:
234 flags
= ARM_TYPE_INT64
;
238 flags
= (cabi
== FFI_VFP
? ARM_TYPE_VFP_S
: ARM_TYPE_INT
);
240 case FFI_TYPE_DOUBLE
:
241 flags
= (cabi
== FFI_VFP
? ARM_TYPE_VFP_D
: ARM_TYPE_INT64
);
244 case FFI_TYPE_STRUCT
:
245 case FFI_TYPE_COMPLEX
:
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
;
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
;
267 flags
= ARM_TYPE_STRUCT
;
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. */
291 /* Perform machine dependent cif processing for variadic calls */
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
)
300 return ffi_prep_cif_machdep (cif
);
303 /* Prototypes for assembly functions, in sysv.S. */
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
;
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
;
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
)
338 flags
= ARM_TYPE_VOID
;
340 else if (flags
== ARM_TYPE_VFP_N
)
342 /* Largest case is double x 4. */
345 else if (flags
== ARM_TYPE_INT
&& rtype
->type
== FFI_TYPE_STRUCT
)
349 vfp_size
= (cif
->abi
== FFI_VFP
&& cif
->vfp_used
? 8*8: 0);
352 stack
= alloca (vfp_size
+ bytes
+ sizeof(struct call_frame
) + rsize
);
361 frame
= (struct call_frame
*)(stack
+ bytes
);
365 new_rvalue
= (void *)(frame
+ 1);
367 frame
->rvalue
= new_rvalue
;
368 frame
->flags
= flags
;
369 frame
->closure
= closure
;
373 ffi_prep_args_VFP (cif
, flags
, new_rvalue
, avalue
, stack
, vfp_space
);
374 ffi_call_VFP (vfp_space
, frame
, fn
, cif
->vfp_used
);
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
);
387 ffi_call (ffi_cif
*cif
, void (*fn
) (void), void *rvalue
, void **avalue
)
389 ffi_call_int (cif
, fn
, rvalue
, avalue
, NULL
);
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
);
400 ffi_prep_incoming_args_SYSV (ffi_cif
*cif
, void *rvalue
,
401 char *argp
, void **avalue
)
403 ffi_type
**arg_types
= cif
->arg_types
;
406 if (cif
->flags
== ARM_TYPE_STRUCT
)
408 rvalue
= *(void **) argp
;
412 for (i
= 0, n
= cif
->nargs
; i
< n
; i
++)
414 ffi_type
*ty
= arg_types
[i
];
417 argp
= ffi_align (ty
, argp
);
418 avalue
[i
] = (void *) argp
;
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
;
431 char *argp
, *regp
, *eo_regp
;
432 char done_with_regs
= 0;
436 eo_regp
= argp
= regp
+ 16;
438 if (cif
->flags
== ARM_TYPE_STRUCT
)
440 rvalue
= *(void **) regp
;
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
);
450 if (vi
< cif
->vfp_nargs
&& is_vfp_type
)
452 avalue
[i
] = vfp_space
+ cif
->vfp_args
[vi
++] * 4;
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
;
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. */
474 FFI_ASSERT (!stack_used
);
487 argp
= ffi_align (ty
, argp
);
488 avalue
[i
] = (void *) argp
;
497 char vfp_space
[8*8] __attribute__((aligned(8)));
503 ffi_closure_inner_SYSV (ffi_cif
*cif
,
504 void (*fun
) (ffi_cif
*, void *, void **, void *),
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
);
516 ffi_closure_inner_VFP (ffi_cif
*cif
,
517 void (*fun
) (ffi_cif
*, void *, void **, void *),
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
);
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>
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 */
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 */
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;
594 /* Try to allocate two pages */
596 vm_allocate (mach_task_self (), &config_page
, PAGE_SIZE
* 2,
598 if (kt
!= KERN_SUCCESS
)
600 fprintf (stderr
, "vm_allocate() failure: %d at %s:%d\n", kt
,
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
,
615 /* Remap the trampoline table to directly follow the config page */
620 vm_remap (mach_task_self (), &trampoline_page
, PAGE_SIZE
, 0x0, FALSE
,
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
,
635 vm_deallocate (mach_task_self (), config_page
, PAGE_SIZE
);
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
));
650 for (i
= 0; i
< table
->free_count
; i
++)
652 ffi_trampoline_table_entry
*entry
= &table
->free_list_pool
[i
];
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
;
667 ffi_closure_alloc (size_t size
, void **code
)
669 /* Create the closure */
670 ffi_closure
*closure
= malloc (size
);
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 ();
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
--;
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
;
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
;
727 /* If all trampolines within this table are free, and at least one other table exists, deallocate
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 */
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
,
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
,
752 /* Deallocate free list */
753 free (table
->free_list_pool
);
756 else if (ffi_trampoline_tables
!= table
)
758 /* Otherwise, bump this table to the top of the list */
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 */
775 extern unsigned int ffi_arm_trampoline
[2] FFI_HIDDEN
;
779 /* the cif must already be prep'ed */
782 ffi_prep_closure_loc (ffi_closure
* closure
,
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. */
793 closure_func
= ffi_closure_VFP
;
795 else if (cif
->abi
!= FFI_SYSV
)
798 #if FFI_EXEC_TRAMPOLINE_TABLE
799 void **config
= FFI_TRAMPOLINE_CODELOC_CONFIG (codeloc
);
801 config
[1] = closure_func
;
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
;
811 closure
->user_data
= user_data
;
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. */
826 closure_func
= ffi_go_closure_VFP
;
828 else if (cif
->abi
!= FFI_SYSV
)
831 closure
->tramp
= closure_func
;
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. */
845 is_hfa0 (const ffi_type
*ty
)
847 ffi_type
**elements
= ty
->elements
;
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
]);
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. */
870 is_hfa1 (const ffi_type
*ty
, int candidate
)
872 ffi_type
**elements
= ty
->elements
;
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
))
884 else if (t
!= candidate
)
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. */
899 vfp_type_p (const ffi_type
*ty
)
903 size_t size
, ele_count
;
905 /* Quickest tests first. */
906 candidate
= ty
->type
;
912 case FFI_TYPE_DOUBLE
:
915 case FFI_TYPE_COMPLEX
:
916 candidate
= ty
->elements
[0]->type
;
917 if (candidate
!= FFI_TYPE_FLOAT
&& candidate
!= FFI_TYPE_DOUBLE
)
921 case FFI_TYPE_STRUCT
:
925 /* No HFA types are smaller than 4 bytes, or larger than 32 bytes. */
927 if (size
< 4 || size
> 32)
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
)
937 candidate
= is_hfa0 (elements
[i
]);
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. */
948 ele_count
= size
/ sizeof(float);
949 if (size
!= ele_count
* sizeof(float))
952 case FFI_TYPE_DOUBLE
:
953 ele_count
= size
/ sizeof(double);
954 if (size
!= ele_count
* sizeof(double))
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
))
972 else if (t
!= candidate
)
976 /* All tests succeeded. Encode the result. */
978 return (ele_count
<< 8) | candidate
;
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)
994 while (reg
+ nregs
<= 16)
997 for (s
= reg
; s
< reg
+ nregs
; s
++)
999 new_used
|= (1 << s
);
1000 if (cif
->vfp_used
& (1 << s
))
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
))
1014 while (cif
->vfp_used
& (1 << reg
))
1016 cif
->vfp_reg_free
= reg
;
1021 // done, mark all regs as used
1022 cif
->vfp_reg_free
= 16;
1023 cif
->vfp_used
= 0xFFFF;
1028 layout_vfp_args (ffi_cif
* cif
)
1031 /* Init VFP fields */
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)