xref: /aosp_15_r20/external/libffi/src/arm/ffi.c (revision 1fd5a2e1d639cd1ddf29dd0c484c123bbd850c21)
1*1fd5a2e1SPrashanth Swaminathan /* -----------------------------------------------------------------------
2*1fd5a2e1SPrashanth Swaminathan    ffi.c - Copyright (c) 2011 Timothy Wall
3*1fd5a2e1SPrashanth Swaminathan            Copyright (c) 2011 Plausible Labs Cooperative, Inc.
4*1fd5a2e1SPrashanth Swaminathan            Copyright (c) 2011 Anthony Green
5*1fd5a2e1SPrashanth Swaminathan 	   Copyright (c) 2011 Free Software Foundation
6*1fd5a2e1SPrashanth Swaminathan            Copyright (c) 1998, 2008, 2011  Red Hat, Inc.
7*1fd5a2e1SPrashanth Swaminathan 
8*1fd5a2e1SPrashanth Swaminathan    ARM Foreign Function Interface
9*1fd5a2e1SPrashanth Swaminathan 
10*1fd5a2e1SPrashanth Swaminathan    Permission is hereby granted, free of charge, to any person obtaining
11*1fd5a2e1SPrashanth Swaminathan    a copy of this software and associated documentation files (the
12*1fd5a2e1SPrashanth Swaminathan    ``Software''), to deal in the Software without restriction, including
13*1fd5a2e1SPrashanth Swaminathan    without limitation the rights to use, copy, modify, merge, publish,
14*1fd5a2e1SPrashanth Swaminathan    distribute, sublicense, and/or sell copies of the Software, and to
15*1fd5a2e1SPrashanth Swaminathan    permit persons to whom the Software is furnished to do so, subject to
16*1fd5a2e1SPrashanth Swaminathan    the following conditions:
17*1fd5a2e1SPrashanth Swaminathan 
18*1fd5a2e1SPrashanth Swaminathan    The above copyright notice and this permission notice shall be included
19*1fd5a2e1SPrashanth Swaminathan    in all copies or substantial portions of the Software.
20*1fd5a2e1SPrashanth Swaminathan 
21*1fd5a2e1SPrashanth Swaminathan    THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND,
22*1fd5a2e1SPrashanth Swaminathan    EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
23*1fd5a2e1SPrashanth Swaminathan    MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
24*1fd5a2e1SPrashanth Swaminathan    NONINFRINGEMENT.  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
25*1fd5a2e1SPrashanth Swaminathan    HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
26*1fd5a2e1SPrashanth Swaminathan    WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
27*1fd5a2e1SPrashanth Swaminathan    OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
28*1fd5a2e1SPrashanth Swaminathan    DEALINGS IN THE SOFTWARE.
29*1fd5a2e1SPrashanth Swaminathan    ----------------------------------------------------------------------- */
30*1fd5a2e1SPrashanth Swaminathan 
31*1fd5a2e1SPrashanth Swaminathan #if defined(__arm__) || defined(_M_ARM)
32*1fd5a2e1SPrashanth Swaminathan #include <fficonfig.h>
33*1fd5a2e1SPrashanth Swaminathan #include <ffi.h>
34*1fd5a2e1SPrashanth Swaminathan #include <ffi_common.h>
35*1fd5a2e1SPrashanth Swaminathan #include <stdint.h>
36*1fd5a2e1SPrashanth Swaminathan #include <stdlib.h>
37*1fd5a2e1SPrashanth Swaminathan #include "internal.h"
38*1fd5a2e1SPrashanth Swaminathan 
39*1fd5a2e1SPrashanth Swaminathan #if defined(_MSC_VER) && defined(_M_ARM)
40*1fd5a2e1SPrashanth Swaminathan #define WIN32_LEAN_AND_MEAN
41*1fd5a2e1SPrashanth Swaminathan #include <windows.h>
42*1fd5a2e1SPrashanth Swaminathan #endif
43*1fd5a2e1SPrashanth Swaminathan 
44*1fd5a2e1SPrashanth Swaminathan #if FFI_EXEC_TRAMPOLINE_TABLE
45*1fd5a2e1SPrashanth Swaminathan 
46*1fd5a2e1SPrashanth Swaminathan #ifdef __MACH__
47*1fd5a2e1SPrashanth Swaminathan #include <mach/machine/vm_param.h>
48*1fd5a2e1SPrashanth Swaminathan #endif
49*1fd5a2e1SPrashanth Swaminathan 
50*1fd5a2e1SPrashanth Swaminathan #else
51*1fd5a2e1SPrashanth Swaminathan #ifndef _M_ARM
52*1fd5a2e1SPrashanth Swaminathan extern unsigned int ffi_arm_trampoline[2] FFI_HIDDEN;
53*1fd5a2e1SPrashanth Swaminathan #else
54*1fd5a2e1SPrashanth Swaminathan extern unsigned int ffi_arm_trampoline[3] FFI_HIDDEN;
55*1fd5a2e1SPrashanth Swaminathan #endif
56*1fd5a2e1SPrashanth Swaminathan #endif
57*1fd5a2e1SPrashanth Swaminathan 
58*1fd5a2e1SPrashanth Swaminathan /* Forward declares. */
59*1fd5a2e1SPrashanth Swaminathan static int vfp_type_p (const ffi_type *);
60*1fd5a2e1SPrashanth Swaminathan static void layout_vfp_args (ffi_cif *);
61*1fd5a2e1SPrashanth Swaminathan 
62*1fd5a2e1SPrashanth Swaminathan static void *
ffi_align(ffi_type * ty,void * p)63*1fd5a2e1SPrashanth Swaminathan ffi_align (ffi_type *ty, void *p)
64*1fd5a2e1SPrashanth Swaminathan {
65*1fd5a2e1SPrashanth Swaminathan   /* Align if necessary */
66*1fd5a2e1SPrashanth Swaminathan   size_t alignment;
67*1fd5a2e1SPrashanth Swaminathan #ifdef _WIN32_WCE
68*1fd5a2e1SPrashanth Swaminathan   alignment = 4;
69*1fd5a2e1SPrashanth Swaminathan #else
70*1fd5a2e1SPrashanth Swaminathan   alignment = ty->alignment;
71*1fd5a2e1SPrashanth Swaminathan   if (alignment < 4)
72*1fd5a2e1SPrashanth Swaminathan     alignment = 4;
73*1fd5a2e1SPrashanth Swaminathan #endif
74*1fd5a2e1SPrashanth Swaminathan   return (void *) FFI_ALIGN (p, alignment);
75*1fd5a2e1SPrashanth Swaminathan }
76*1fd5a2e1SPrashanth Swaminathan 
77*1fd5a2e1SPrashanth Swaminathan static size_t
ffi_put_arg(ffi_type * ty,void * src,void * dst)78*1fd5a2e1SPrashanth Swaminathan ffi_put_arg (ffi_type *ty, void *src, void *dst)
79*1fd5a2e1SPrashanth Swaminathan {
80*1fd5a2e1SPrashanth Swaminathan   size_t z = ty->size;
81*1fd5a2e1SPrashanth Swaminathan 
82*1fd5a2e1SPrashanth Swaminathan   switch (ty->type)
83*1fd5a2e1SPrashanth Swaminathan     {
84*1fd5a2e1SPrashanth Swaminathan     case FFI_TYPE_SINT8:
85*1fd5a2e1SPrashanth Swaminathan       *(UINT32 *)dst = *(SINT8 *)src;
86*1fd5a2e1SPrashanth Swaminathan       break;
87*1fd5a2e1SPrashanth Swaminathan     case FFI_TYPE_UINT8:
88*1fd5a2e1SPrashanth Swaminathan       *(UINT32 *)dst = *(UINT8 *)src;
89*1fd5a2e1SPrashanth Swaminathan       break;
90*1fd5a2e1SPrashanth Swaminathan     case FFI_TYPE_SINT16:
91*1fd5a2e1SPrashanth Swaminathan       *(UINT32 *)dst = *(SINT16 *)src;
92*1fd5a2e1SPrashanth Swaminathan       break;
93*1fd5a2e1SPrashanth Swaminathan     case FFI_TYPE_UINT16:
94*1fd5a2e1SPrashanth Swaminathan       *(UINT32 *)dst = *(UINT16 *)src;
95*1fd5a2e1SPrashanth Swaminathan       break;
96*1fd5a2e1SPrashanth Swaminathan 
97*1fd5a2e1SPrashanth Swaminathan     case FFI_TYPE_INT:
98*1fd5a2e1SPrashanth Swaminathan     case FFI_TYPE_SINT32:
99*1fd5a2e1SPrashanth Swaminathan     case FFI_TYPE_UINT32:
100*1fd5a2e1SPrashanth Swaminathan     case FFI_TYPE_POINTER:
101*1fd5a2e1SPrashanth Swaminathan #ifndef _MSC_VER
102*1fd5a2e1SPrashanth Swaminathan     case FFI_TYPE_FLOAT:
103*1fd5a2e1SPrashanth Swaminathan #endif
104*1fd5a2e1SPrashanth Swaminathan       *(UINT32 *)dst = *(UINT32 *)src;
105*1fd5a2e1SPrashanth Swaminathan       break;
106*1fd5a2e1SPrashanth Swaminathan 
107*1fd5a2e1SPrashanth Swaminathan #ifdef _MSC_VER
108*1fd5a2e1SPrashanth Swaminathan     // casting a float* to a UINT32* doesn't work on Windows
109*1fd5a2e1SPrashanth Swaminathan     case FFI_TYPE_FLOAT:
110*1fd5a2e1SPrashanth Swaminathan         *(uintptr_t *)dst = 0;
111*1fd5a2e1SPrashanth Swaminathan         *(float *)dst = *(float *)src;
112*1fd5a2e1SPrashanth Swaminathan         break;
113*1fd5a2e1SPrashanth Swaminathan #endif
114*1fd5a2e1SPrashanth Swaminathan 
115*1fd5a2e1SPrashanth Swaminathan     case FFI_TYPE_SINT64:
116*1fd5a2e1SPrashanth Swaminathan     case FFI_TYPE_UINT64:
117*1fd5a2e1SPrashanth Swaminathan     case FFI_TYPE_DOUBLE:
118*1fd5a2e1SPrashanth Swaminathan       *(UINT64 *)dst = *(UINT64 *)src;
119*1fd5a2e1SPrashanth Swaminathan       break;
120*1fd5a2e1SPrashanth Swaminathan 
121*1fd5a2e1SPrashanth Swaminathan     case FFI_TYPE_STRUCT:
122*1fd5a2e1SPrashanth Swaminathan     case FFI_TYPE_COMPLEX:
123*1fd5a2e1SPrashanth Swaminathan       memcpy (dst, src, z);
124*1fd5a2e1SPrashanth Swaminathan       break;
125*1fd5a2e1SPrashanth Swaminathan 
126*1fd5a2e1SPrashanth Swaminathan     default:
127*1fd5a2e1SPrashanth Swaminathan       abort();
128*1fd5a2e1SPrashanth Swaminathan     }
129*1fd5a2e1SPrashanth Swaminathan 
130*1fd5a2e1SPrashanth Swaminathan   return FFI_ALIGN (z, 4);
131*1fd5a2e1SPrashanth Swaminathan }
132*1fd5a2e1SPrashanth Swaminathan 
133*1fd5a2e1SPrashanth Swaminathan /* ffi_prep_args is called once stack space has been allocated
134*1fd5a2e1SPrashanth Swaminathan    for the function's arguments.
135*1fd5a2e1SPrashanth Swaminathan 
136*1fd5a2e1SPrashanth Swaminathan    The vfp_space parameter is the load area for VFP regs, the return
137*1fd5a2e1SPrashanth Swaminathan    value is cif->vfp_used (word bitset of VFP regs used for passing
138*1fd5a2e1SPrashanth Swaminathan    arguments). These are only used for the VFP hard-float ABI.
139*1fd5a2e1SPrashanth Swaminathan */
140*1fd5a2e1SPrashanth Swaminathan static void
ffi_prep_args_SYSV(ffi_cif * cif,int flags,void * rvalue,void ** avalue,char * argp)141*1fd5a2e1SPrashanth Swaminathan ffi_prep_args_SYSV (ffi_cif *cif, int flags, void *rvalue,
142*1fd5a2e1SPrashanth Swaminathan 		    void **avalue, char *argp)
143*1fd5a2e1SPrashanth Swaminathan {
144*1fd5a2e1SPrashanth Swaminathan   ffi_type **arg_types = cif->arg_types;
145*1fd5a2e1SPrashanth Swaminathan   int i, n;
146*1fd5a2e1SPrashanth Swaminathan 
147*1fd5a2e1SPrashanth Swaminathan   if (flags == ARM_TYPE_STRUCT)
148*1fd5a2e1SPrashanth Swaminathan     {
149*1fd5a2e1SPrashanth Swaminathan       *(void **) argp = rvalue;
150*1fd5a2e1SPrashanth Swaminathan       argp += 4;
151*1fd5a2e1SPrashanth Swaminathan     }
152*1fd5a2e1SPrashanth Swaminathan 
153*1fd5a2e1SPrashanth Swaminathan   for (i = 0, n = cif->nargs; i < n; i++)
154*1fd5a2e1SPrashanth Swaminathan     {
155*1fd5a2e1SPrashanth Swaminathan       ffi_type *ty = arg_types[i];
156*1fd5a2e1SPrashanth Swaminathan       argp = ffi_align (ty, argp);
157*1fd5a2e1SPrashanth Swaminathan       argp += ffi_put_arg (ty, avalue[i], argp);
158*1fd5a2e1SPrashanth Swaminathan     }
159*1fd5a2e1SPrashanth Swaminathan }
160*1fd5a2e1SPrashanth Swaminathan 
161*1fd5a2e1SPrashanth Swaminathan static void
ffi_prep_args_VFP(ffi_cif * cif,int flags,void * rvalue,void ** avalue,char * stack,char * vfp_space)162*1fd5a2e1SPrashanth Swaminathan ffi_prep_args_VFP (ffi_cif *cif, int flags, void *rvalue,
163*1fd5a2e1SPrashanth Swaminathan                    void **avalue, char *stack, char *vfp_space)
164*1fd5a2e1SPrashanth Swaminathan {
165*1fd5a2e1SPrashanth Swaminathan   ffi_type **arg_types = cif->arg_types;
166*1fd5a2e1SPrashanth Swaminathan   int i, n, vi = 0;
167*1fd5a2e1SPrashanth Swaminathan   char *argp, *regp, *eo_regp;
168*1fd5a2e1SPrashanth Swaminathan   char stack_used = 0;
169*1fd5a2e1SPrashanth Swaminathan   char done_with_regs = 0;
170*1fd5a2e1SPrashanth Swaminathan 
171*1fd5a2e1SPrashanth Swaminathan   /* The first 4 words on the stack are used for values
172*1fd5a2e1SPrashanth Swaminathan      passed in core registers.  */
173*1fd5a2e1SPrashanth Swaminathan   regp = stack;
174*1fd5a2e1SPrashanth Swaminathan   eo_regp = argp = regp + 16;
175*1fd5a2e1SPrashanth Swaminathan 
176*1fd5a2e1SPrashanth Swaminathan   /* If the function returns an FFI_TYPE_STRUCT in memory,
177*1fd5a2e1SPrashanth Swaminathan      that address is passed in r0 to the function.  */
178*1fd5a2e1SPrashanth Swaminathan   if (flags == ARM_TYPE_STRUCT)
179*1fd5a2e1SPrashanth Swaminathan     {
180*1fd5a2e1SPrashanth Swaminathan       *(void **) regp = rvalue;
181*1fd5a2e1SPrashanth Swaminathan       regp += 4;
182*1fd5a2e1SPrashanth Swaminathan     }
183*1fd5a2e1SPrashanth Swaminathan 
184*1fd5a2e1SPrashanth Swaminathan   for (i = 0, n = cif->nargs; i < n; i++)
185*1fd5a2e1SPrashanth Swaminathan     {
186*1fd5a2e1SPrashanth Swaminathan       ffi_type *ty = arg_types[i];
187*1fd5a2e1SPrashanth Swaminathan       void *a = avalue[i];
188*1fd5a2e1SPrashanth Swaminathan       int is_vfp_type = vfp_type_p (ty);
189*1fd5a2e1SPrashanth Swaminathan 
190*1fd5a2e1SPrashanth Swaminathan       /* Allocated in VFP registers. */
191*1fd5a2e1SPrashanth Swaminathan       if (vi < cif->vfp_nargs && is_vfp_type)
192*1fd5a2e1SPrashanth Swaminathan 	{
193*1fd5a2e1SPrashanth Swaminathan 	  char *vfp_slot = vfp_space + cif->vfp_args[vi++] * 4;
194*1fd5a2e1SPrashanth Swaminathan 	  ffi_put_arg (ty, a, vfp_slot);
195*1fd5a2e1SPrashanth Swaminathan 	  continue;
196*1fd5a2e1SPrashanth Swaminathan 	}
197*1fd5a2e1SPrashanth Swaminathan       /* Try allocating in core registers. */
198*1fd5a2e1SPrashanth Swaminathan       else if (!done_with_regs && !is_vfp_type)
199*1fd5a2e1SPrashanth Swaminathan 	{
200*1fd5a2e1SPrashanth Swaminathan 	  char *tregp = ffi_align (ty, regp);
201*1fd5a2e1SPrashanth Swaminathan 	  size_t size = ty->size;
202*1fd5a2e1SPrashanth Swaminathan 	  size = (size < 4) ? 4 : size;	// pad
203*1fd5a2e1SPrashanth Swaminathan 	  /* Check if there is space left in the aligned register
204*1fd5a2e1SPrashanth Swaminathan 	     area to place the argument.  */
205*1fd5a2e1SPrashanth Swaminathan 	  if (tregp + size <= eo_regp)
206*1fd5a2e1SPrashanth Swaminathan 	    {
207*1fd5a2e1SPrashanth Swaminathan 	      regp = tregp + ffi_put_arg (ty, a, tregp);
208*1fd5a2e1SPrashanth Swaminathan 	      done_with_regs = (regp == argp);
209*1fd5a2e1SPrashanth Swaminathan 	      // ensure we did not write into the stack area
210*1fd5a2e1SPrashanth Swaminathan 	      FFI_ASSERT (regp <= argp);
211*1fd5a2e1SPrashanth Swaminathan 	      continue;
212*1fd5a2e1SPrashanth Swaminathan 	    }
213*1fd5a2e1SPrashanth Swaminathan 	  /* In case there are no arguments in the stack area yet,
214*1fd5a2e1SPrashanth Swaminathan 	     the argument is passed in the remaining core registers
215*1fd5a2e1SPrashanth Swaminathan 	     and on the stack.  */
216*1fd5a2e1SPrashanth Swaminathan 	  else if (!stack_used)
217*1fd5a2e1SPrashanth Swaminathan 	    {
218*1fd5a2e1SPrashanth Swaminathan 	      stack_used = 1;
219*1fd5a2e1SPrashanth Swaminathan 	      done_with_regs = 1;
220*1fd5a2e1SPrashanth Swaminathan 	      argp = tregp + ffi_put_arg (ty, a, tregp);
221*1fd5a2e1SPrashanth Swaminathan 	      FFI_ASSERT (eo_regp < argp);
222*1fd5a2e1SPrashanth Swaminathan 	      continue;
223*1fd5a2e1SPrashanth Swaminathan 	    }
224*1fd5a2e1SPrashanth Swaminathan 	}
225*1fd5a2e1SPrashanth Swaminathan       /* Base case, arguments are passed on the stack */
226*1fd5a2e1SPrashanth Swaminathan       stack_used = 1;
227*1fd5a2e1SPrashanth Swaminathan       argp = ffi_align (ty, argp);
228*1fd5a2e1SPrashanth Swaminathan       argp += ffi_put_arg (ty, a, argp);
229*1fd5a2e1SPrashanth Swaminathan     }
230*1fd5a2e1SPrashanth Swaminathan }
231*1fd5a2e1SPrashanth Swaminathan 
232*1fd5a2e1SPrashanth Swaminathan /* Perform machine dependent cif processing */
233*1fd5a2e1SPrashanth Swaminathan ffi_status FFI_HIDDEN
ffi_prep_cif_machdep(ffi_cif * cif)234*1fd5a2e1SPrashanth Swaminathan ffi_prep_cif_machdep (ffi_cif *cif)
235*1fd5a2e1SPrashanth Swaminathan {
236*1fd5a2e1SPrashanth Swaminathan   int flags = 0, cabi = cif->abi;
237*1fd5a2e1SPrashanth Swaminathan   size_t bytes = cif->bytes;
238*1fd5a2e1SPrashanth Swaminathan 
239*1fd5a2e1SPrashanth Swaminathan   /* Map out the register placements of VFP register args.  The VFP
240*1fd5a2e1SPrashanth Swaminathan      hard-float calling conventions are slightly more sophisticated
241*1fd5a2e1SPrashanth Swaminathan      than the base calling conventions, so we do it here instead of
242*1fd5a2e1SPrashanth Swaminathan      in ffi_prep_args(). */
243*1fd5a2e1SPrashanth Swaminathan   if (cabi == FFI_VFP)
244*1fd5a2e1SPrashanth Swaminathan     layout_vfp_args (cif);
245*1fd5a2e1SPrashanth Swaminathan 
246*1fd5a2e1SPrashanth Swaminathan   /* Set the return type flag */
247*1fd5a2e1SPrashanth Swaminathan   switch (cif->rtype->type)
248*1fd5a2e1SPrashanth Swaminathan     {
249*1fd5a2e1SPrashanth Swaminathan     case FFI_TYPE_VOID:
250*1fd5a2e1SPrashanth Swaminathan       flags = ARM_TYPE_VOID;
251*1fd5a2e1SPrashanth Swaminathan       break;
252*1fd5a2e1SPrashanth Swaminathan 
253*1fd5a2e1SPrashanth Swaminathan     case FFI_TYPE_INT:
254*1fd5a2e1SPrashanth Swaminathan     case FFI_TYPE_UINT8:
255*1fd5a2e1SPrashanth Swaminathan     case FFI_TYPE_SINT8:
256*1fd5a2e1SPrashanth Swaminathan     case FFI_TYPE_UINT16:
257*1fd5a2e1SPrashanth Swaminathan     case FFI_TYPE_SINT16:
258*1fd5a2e1SPrashanth Swaminathan     case FFI_TYPE_UINT32:
259*1fd5a2e1SPrashanth Swaminathan     case FFI_TYPE_SINT32:
260*1fd5a2e1SPrashanth Swaminathan     case FFI_TYPE_POINTER:
261*1fd5a2e1SPrashanth Swaminathan       flags = ARM_TYPE_INT;
262*1fd5a2e1SPrashanth Swaminathan       break;
263*1fd5a2e1SPrashanth Swaminathan 
264*1fd5a2e1SPrashanth Swaminathan     case FFI_TYPE_SINT64:
265*1fd5a2e1SPrashanth Swaminathan     case FFI_TYPE_UINT64:
266*1fd5a2e1SPrashanth Swaminathan       flags = ARM_TYPE_INT64;
267*1fd5a2e1SPrashanth Swaminathan       break;
268*1fd5a2e1SPrashanth Swaminathan 
269*1fd5a2e1SPrashanth Swaminathan     case FFI_TYPE_FLOAT:
270*1fd5a2e1SPrashanth Swaminathan       flags = (cabi == FFI_VFP ? ARM_TYPE_VFP_S : ARM_TYPE_INT);
271*1fd5a2e1SPrashanth Swaminathan       break;
272*1fd5a2e1SPrashanth Swaminathan     case FFI_TYPE_DOUBLE:
273*1fd5a2e1SPrashanth Swaminathan       flags = (cabi == FFI_VFP ? ARM_TYPE_VFP_D : ARM_TYPE_INT64);
274*1fd5a2e1SPrashanth Swaminathan       break;
275*1fd5a2e1SPrashanth Swaminathan 
276*1fd5a2e1SPrashanth Swaminathan     case FFI_TYPE_STRUCT:
277*1fd5a2e1SPrashanth Swaminathan     case FFI_TYPE_COMPLEX:
278*1fd5a2e1SPrashanth Swaminathan       if (cabi == FFI_VFP)
279*1fd5a2e1SPrashanth Swaminathan 	{
280*1fd5a2e1SPrashanth Swaminathan 	  int h = vfp_type_p (cif->rtype);
281*1fd5a2e1SPrashanth Swaminathan 
282*1fd5a2e1SPrashanth Swaminathan 	  flags = ARM_TYPE_VFP_N;
283*1fd5a2e1SPrashanth Swaminathan 	  if (h == 0x100 + FFI_TYPE_FLOAT)
284*1fd5a2e1SPrashanth Swaminathan 	    flags = ARM_TYPE_VFP_S;
285*1fd5a2e1SPrashanth Swaminathan 	  if (h == 0x100 + FFI_TYPE_DOUBLE)
286*1fd5a2e1SPrashanth Swaminathan 	    flags = ARM_TYPE_VFP_D;
287*1fd5a2e1SPrashanth Swaminathan 	  if (h != 0)
288*1fd5a2e1SPrashanth Swaminathan 	      break;
289*1fd5a2e1SPrashanth Swaminathan 	}
290*1fd5a2e1SPrashanth Swaminathan 
291*1fd5a2e1SPrashanth Swaminathan       /* A Composite Type not larger than 4 bytes is returned in r0.
292*1fd5a2e1SPrashanth Swaminathan 	 A Composite Type larger than 4 bytes, or whose size cannot
293*1fd5a2e1SPrashanth Swaminathan 	 be determined statically ... is stored in memory at an
294*1fd5a2e1SPrashanth Swaminathan 	 address passed [in r0].  */
295*1fd5a2e1SPrashanth Swaminathan       if (cif->rtype->size <= 4)
296*1fd5a2e1SPrashanth Swaminathan 	flags = ARM_TYPE_INT;
297*1fd5a2e1SPrashanth Swaminathan       else
298*1fd5a2e1SPrashanth Swaminathan 	{
299*1fd5a2e1SPrashanth Swaminathan 	  flags = ARM_TYPE_STRUCT;
300*1fd5a2e1SPrashanth Swaminathan 	  bytes += 4;
301*1fd5a2e1SPrashanth Swaminathan 	}
302*1fd5a2e1SPrashanth Swaminathan       break;
303*1fd5a2e1SPrashanth Swaminathan 
304*1fd5a2e1SPrashanth Swaminathan     default:
305*1fd5a2e1SPrashanth Swaminathan       abort();
306*1fd5a2e1SPrashanth Swaminathan     }
307*1fd5a2e1SPrashanth Swaminathan 
308*1fd5a2e1SPrashanth Swaminathan   /* Round the stack up to a multiple of 8 bytes.  This isn't needed
309*1fd5a2e1SPrashanth Swaminathan      everywhere, but it is on some platforms, and it doesn't harm anything
310*1fd5a2e1SPrashanth Swaminathan      when it isn't needed.  */
311*1fd5a2e1SPrashanth Swaminathan   bytes = FFI_ALIGN (bytes, 8);
312*1fd5a2e1SPrashanth Swaminathan 
313*1fd5a2e1SPrashanth Swaminathan   /* Minimum stack space is the 4 register arguments that we pop.  */
314*1fd5a2e1SPrashanth Swaminathan   if (bytes < 4*4)
315*1fd5a2e1SPrashanth Swaminathan     bytes = 4*4;
316*1fd5a2e1SPrashanth Swaminathan 
317*1fd5a2e1SPrashanth Swaminathan   cif->bytes = bytes;
318*1fd5a2e1SPrashanth Swaminathan   cif->flags = flags;
319*1fd5a2e1SPrashanth Swaminathan 
320*1fd5a2e1SPrashanth Swaminathan   return FFI_OK;
321*1fd5a2e1SPrashanth Swaminathan }
322*1fd5a2e1SPrashanth Swaminathan 
323*1fd5a2e1SPrashanth Swaminathan /* Perform machine dependent cif processing for variadic calls */
324*1fd5a2e1SPrashanth Swaminathan ffi_status FFI_HIDDEN
ffi_prep_cif_machdep_var(ffi_cif * cif,unsigned int nfixedargs,unsigned int ntotalargs)325*1fd5a2e1SPrashanth Swaminathan ffi_prep_cif_machdep_var (ffi_cif * cif,
326*1fd5a2e1SPrashanth Swaminathan 			  unsigned int nfixedargs, unsigned int ntotalargs)
327*1fd5a2e1SPrashanth Swaminathan {
328*1fd5a2e1SPrashanth Swaminathan   /* VFP variadic calls actually use the SYSV ABI */
329*1fd5a2e1SPrashanth Swaminathan   if (cif->abi == FFI_VFP)
330*1fd5a2e1SPrashanth Swaminathan     cif->abi = FFI_SYSV;
331*1fd5a2e1SPrashanth Swaminathan 
332*1fd5a2e1SPrashanth Swaminathan   return ffi_prep_cif_machdep (cif);
333*1fd5a2e1SPrashanth Swaminathan }
334*1fd5a2e1SPrashanth Swaminathan 
335*1fd5a2e1SPrashanth Swaminathan /* Prototypes for assembly functions, in sysv.S.  */
336*1fd5a2e1SPrashanth Swaminathan 
337*1fd5a2e1SPrashanth Swaminathan struct call_frame
338*1fd5a2e1SPrashanth Swaminathan {
339*1fd5a2e1SPrashanth Swaminathan   void *fp;
340*1fd5a2e1SPrashanth Swaminathan   void *lr;
341*1fd5a2e1SPrashanth Swaminathan   void *rvalue;
342*1fd5a2e1SPrashanth Swaminathan   int flags;
343*1fd5a2e1SPrashanth Swaminathan   void *closure;
344*1fd5a2e1SPrashanth Swaminathan };
345*1fd5a2e1SPrashanth Swaminathan 
346*1fd5a2e1SPrashanth Swaminathan extern void ffi_call_SYSV (void *stack, struct call_frame *,
347*1fd5a2e1SPrashanth Swaminathan 			   void (*fn) (void)) FFI_HIDDEN;
348*1fd5a2e1SPrashanth Swaminathan extern void ffi_call_VFP (void *vfp_space, struct call_frame *,
349*1fd5a2e1SPrashanth Swaminathan 			   void (*fn) (void), unsigned vfp_used) FFI_HIDDEN;
350*1fd5a2e1SPrashanth Swaminathan 
351*1fd5a2e1SPrashanth Swaminathan static void
ffi_call_int(ffi_cif * cif,void (* fn)(void),void * rvalue,void ** avalue,void * closure)352*1fd5a2e1SPrashanth Swaminathan ffi_call_int (ffi_cif * cif, void (*fn) (void), void *rvalue,
353*1fd5a2e1SPrashanth Swaminathan 	      void **avalue, void *closure)
354*1fd5a2e1SPrashanth Swaminathan {
355*1fd5a2e1SPrashanth Swaminathan   int flags = cif->flags;
356*1fd5a2e1SPrashanth Swaminathan   ffi_type *rtype = cif->rtype;
357*1fd5a2e1SPrashanth Swaminathan   size_t bytes, rsize, vfp_size;
358*1fd5a2e1SPrashanth Swaminathan   char *stack, *vfp_space, *new_rvalue;
359*1fd5a2e1SPrashanth Swaminathan   struct call_frame *frame;
360*1fd5a2e1SPrashanth Swaminathan 
361*1fd5a2e1SPrashanth Swaminathan   rsize = 0;
362*1fd5a2e1SPrashanth Swaminathan   if (rvalue == NULL)
363*1fd5a2e1SPrashanth Swaminathan     {
364*1fd5a2e1SPrashanth Swaminathan       /* If the return value is a struct and we don't have a return
365*1fd5a2e1SPrashanth Swaminathan 	 value address then we need to make one.  Otherwise the return
366*1fd5a2e1SPrashanth Swaminathan 	 value is in registers and we can ignore them.  */
367*1fd5a2e1SPrashanth Swaminathan       if (flags == ARM_TYPE_STRUCT)
368*1fd5a2e1SPrashanth Swaminathan 	rsize = rtype->size;
369*1fd5a2e1SPrashanth Swaminathan       else
370*1fd5a2e1SPrashanth Swaminathan 	flags = ARM_TYPE_VOID;
371*1fd5a2e1SPrashanth Swaminathan     }
372*1fd5a2e1SPrashanth Swaminathan   else if (flags == ARM_TYPE_VFP_N)
373*1fd5a2e1SPrashanth Swaminathan     {
374*1fd5a2e1SPrashanth Swaminathan       /* Largest case is double x 4. */
375*1fd5a2e1SPrashanth Swaminathan       rsize = 32;
376*1fd5a2e1SPrashanth Swaminathan     }
377*1fd5a2e1SPrashanth Swaminathan   else if (flags == ARM_TYPE_INT && rtype->type == FFI_TYPE_STRUCT)
378*1fd5a2e1SPrashanth Swaminathan     rsize = 4;
379*1fd5a2e1SPrashanth Swaminathan 
380*1fd5a2e1SPrashanth Swaminathan   /* Largest case.  */
381*1fd5a2e1SPrashanth Swaminathan   vfp_size = (cif->abi == FFI_VFP && cif->vfp_used ? 8*8: 0);
382*1fd5a2e1SPrashanth Swaminathan 
383*1fd5a2e1SPrashanth Swaminathan   bytes = cif->bytes;
384*1fd5a2e1SPrashanth Swaminathan   stack = alloca (vfp_size + bytes + sizeof(struct call_frame) + rsize);
385*1fd5a2e1SPrashanth Swaminathan 
386*1fd5a2e1SPrashanth Swaminathan   vfp_space = NULL;
387*1fd5a2e1SPrashanth Swaminathan   if (vfp_size)
388*1fd5a2e1SPrashanth Swaminathan     {
389*1fd5a2e1SPrashanth Swaminathan       vfp_space = stack;
390*1fd5a2e1SPrashanth Swaminathan       stack += vfp_size;
391*1fd5a2e1SPrashanth Swaminathan     }
392*1fd5a2e1SPrashanth Swaminathan 
393*1fd5a2e1SPrashanth Swaminathan   frame = (struct call_frame *)(stack + bytes);
394*1fd5a2e1SPrashanth Swaminathan 
395*1fd5a2e1SPrashanth Swaminathan   new_rvalue = rvalue;
396*1fd5a2e1SPrashanth Swaminathan   if (rsize)
397*1fd5a2e1SPrashanth Swaminathan     new_rvalue = (void *)(frame + 1);
398*1fd5a2e1SPrashanth Swaminathan 
399*1fd5a2e1SPrashanth Swaminathan   frame->rvalue = new_rvalue;
400*1fd5a2e1SPrashanth Swaminathan   frame->flags = flags;
401*1fd5a2e1SPrashanth Swaminathan   frame->closure = closure;
402*1fd5a2e1SPrashanth Swaminathan 
403*1fd5a2e1SPrashanth Swaminathan   if (vfp_space)
404*1fd5a2e1SPrashanth Swaminathan     {
405*1fd5a2e1SPrashanth Swaminathan       ffi_prep_args_VFP (cif, flags, new_rvalue, avalue, stack, vfp_space);
406*1fd5a2e1SPrashanth Swaminathan       ffi_call_VFP (vfp_space, frame, fn, cif->vfp_used);
407*1fd5a2e1SPrashanth Swaminathan     }
408*1fd5a2e1SPrashanth Swaminathan   else
409*1fd5a2e1SPrashanth Swaminathan     {
410*1fd5a2e1SPrashanth Swaminathan       ffi_prep_args_SYSV (cif, flags, new_rvalue, avalue, stack);
411*1fd5a2e1SPrashanth Swaminathan       ffi_call_SYSV (stack, frame, fn);
412*1fd5a2e1SPrashanth Swaminathan     }
413*1fd5a2e1SPrashanth Swaminathan 
414*1fd5a2e1SPrashanth Swaminathan   if (rvalue && rvalue != new_rvalue)
415*1fd5a2e1SPrashanth Swaminathan     memcpy (rvalue, new_rvalue, rtype->size);
416*1fd5a2e1SPrashanth Swaminathan }
417*1fd5a2e1SPrashanth Swaminathan 
418*1fd5a2e1SPrashanth Swaminathan void
ffi_call(ffi_cif * cif,void (* fn)(void),void * rvalue,void ** avalue)419*1fd5a2e1SPrashanth Swaminathan ffi_call (ffi_cif *cif, void (*fn) (void), void *rvalue, void **avalue)
420*1fd5a2e1SPrashanth Swaminathan {
421*1fd5a2e1SPrashanth Swaminathan   ffi_call_int (cif, fn, rvalue, avalue, NULL);
422*1fd5a2e1SPrashanth Swaminathan }
423*1fd5a2e1SPrashanth Swaminathan 
424*1fd5a2e1SPrashanth Swaminathan void
ffi_call_go(ffi_cif * cif,void (* fn)(void),void * rvalue,void ** avalue,void * closure)425*1fd5a2e1SPrashanth Swaminathan ffi_call_go (ffi_cif *cif, void (*fn) (void), void *rvalue,
426*1fd5a2e1SPrashanth Swaminathan 	     void **avalue, void *closure)
427*1fd5a2e1SPrashanth Swaminathan {
428*1fd5a2e1SPrashanth Swaminathan   ffi_call_int (cif, fn, rvalue, avalue, closure);
429*1fd5a2e1SPrashanth Swaminathan }
430*1fd5a2e1SPrashanth Swaminathan 
431*1fd5a2e1SPrashanth Swaminathan static void *
ffi_prep_incoming_args_SYSV(ffi_cif * cif,void * rvalue,char * argp,void ** avalue)432*1fd5a2e1SPrashanth Swaminathan ffi_prep_incoming_args_SYSV (ffi_cif *cif, void *rvalue,
433*1fd5a2e1SPrashanth Swaminathan 			     char *argp, void **avalue)
434*1fd5a2e1SPrashanth Swaminathan {
435*1fd5a2e1SPrashanth Swaminathan   ffi_type **arg_types = cif->arg_types;
436*1fd5a2e1SPrashanth Swaminathan   int i, n;
437*1fd5a2e1SPrashanth Swaminathan 
438*1fd5a2e1SPrashanth Swaminathan   if (cif->flags == ARM_TYPE_STRUCT)
439*1fd5a2e1SPrashanth Swaminathan     {
440*1fd5a2e1SPrashanth Swaminathan       rvalue = *(void **) argp;
441*1fd5a2e1SPrashanth Swaminathan       argp += 4;
442*1fd5a2e1SPrashanth Swaminathan     }
443*1fd5a2e1SPrashanth Swaminathan   else
444*1fd5a2e1SPrashanth Swaminathan     {
445*1fd5a2e1SPrashanth Swaminathan       if (cif->rtype->size && cif->rtype->size < 4)
446*1fd5a2e1SPrashanth Swaminathan         *(uint32_t *) rvalue = 0;
447*1fd5a2e1SPrashanth Swaminathan     }
448*1fd5a2e1SPrashanth Swaminathan 
449*1fd5a2e1SPrashanth Swaminathan   for (i = 0, n = cif->nargs; i < n; i++)
450*1fd5a2e1SPrashanth Swaminathan     {
451*1fd5a2e1SPrashanth Swaminathan       ffi_type *ty = arg_types[i];
452*1fd5a2e1SPrashanth Swaminathan       size_t z = ty->size;
453*1fd5a2e1SPrashanth Swaminathan 
454*1fd5a2e1SPrashanth Swaminathan       argp = ffi_align (ty, argp);
455*1fd5a2e1SPrashanth Swaminathan       avalue[i] = (void *) argp;
456*1fd5a2e1SPrashanth Swaminathan       argp += z;
457*1fd5a2e1SPrashanth Swaminathan     }
458*1fd5a2e1SPrashanth Swaminathan 
459*1fd5a2e1SPrashanth Swaminathan   return rvalue;
460*1fd5a2e1SPrashanth Swaminathan }
461*1fd5a2e1SPrashanth Swaminathan 
462*1fd5a2e1SPrashanth Swaminathan static void *
ffi_prep_incoming_args_VFP(ffi_cif * cif,void * rvalue,char * stack,char * vfp_space,void ** avalue)463*1fd5a2e1SPrashanth Swaminathan ffi_prep_incoming_args_VFP (ffi_cif *cif, void *rvalue, char *stack,
464*1fd5a2e1SPrashanth Swaminathan 			    char *vfp_space, void **avalue)
465*1fd5a2e1SPrashanth Swaminathan {
466*1fd5a2e1SPrashanth Swaminathan   ffi_type **arg_types = cif->arg_types;
467*1fd5a2e1SPrashanth Swaminathan   int i, n, vi = 0;
468*1fd5a2e1SPrashanth Swaminathan   char *argp, *regp, *eo_regp;
469*1fd5a2e1SPrashanth Swaminathan   char done_with_regs = 0;
470*1fd5a2e1SPrashanth Swaminathan   char stack_used = 0;
471*1fd5a2e1SPrashanth Swaminathan 
472*1fd5a2e1SPrashanth Swaminathan   regp = stack;
473*1fd5a2e1SPrashanth Swaminathan   eo_regp = argp = regp + 16;
474*1fd5a2e1SPrashanth Swaminathan 
475*1fd5a2e1SPrashanth Swaminathan   if (cif->flags == ARM_TYPE_STRUCT)
476*1fd5a2e1SPrashanth Swaminathan     {
477*1fd5a2e1SPrashanth Swaminathan       rvalue = *(void **) regp;
478*1fd5a2e1SPrashanth Swaminathan       regp += 4;
479*1fd5a2e1SPrashanth Swaminathan     }
480*1fd5a2e1SPrashanth Swaminathan 
481*1fd5a2e1SPrashanth Swaminathan   for (i = 0, n = cif->nargs; i < n; i++)
482*1fd5a2e1SPrashanth Swaminathan     {
483*1fd5a2e1SPrashanth Swaminathan       ffi_type *ty = arg_types[i];
484*1fd5a2e1SPrashanth Swaminathan       int is_vfp_type = vfp_type_p (ty);
485*1fd5a2e1SPrashanth Swaminathan       size_t z = ty->size;
486*1fd5a2e1SPrashanth Swaminathan 
487*1fd5a2e1SPrashanth Swaminathan       if (vi < cif->vfp_nargs && is_vfp_type)
488*1fd5a2e1SPrashanth Swaminathan 	{
489*1fd5a2e1SPrashanth Swaminathan 	  avalue[i] = vfp_space + cif->vfp_args[vi++] * 4;
490*1fd5a2e1SPrashanth Swaminathan 	  continue;
491*1fd5a2e1SPrashanth Swaminathan 	}
492*1fd5a2e1SPrashanth Swaminathan       else if (!done_with_regs && !is_vfp_type)
493*1fd5a2e1SPrashanth Swaminathan 	{
494*1fd5a2e1SPrashanth Swaminathan 	  char *tregp = ffi_align (ty, regp);
495*1fd5a2e1SPrashanth Swaminathan 
496*1fd5a2e1SPrashanth Swaminathan 	  z = (z < 4) ? 4 : z;	// pad
497*1fd5a2e1SPrashanth Swaminathan 
498*1fd5a2e1SPrashanth Swaminathan 	  /* If the arguments either fits into the registers or uses registers
499*1fd5a2e1SPrashanth Swaminathan 	     and stack, while we haven't read other things from the stack */
500*1fd5a2e1SPrashanth Swaminathan 	  if (tregp + z <= eo_regp || !stack_used)
501*1fd5a2e1SPrashanth Swaminathan 	    {
502*1fd5a2e1SPrashanth Swaminathan 	      /* Because we're little endian, this is what it turns into.  */
503*1fd5a2e1SPrashanth Swaminathan 	      avalue[i] = (void *) tregp;
504*1fd5a2e1SPrashanth Swaminathan 	      regp = tregp + z;
505*1fd5a2e1SPrashanth Swaminathan 
506*1fd5a2e1SPrashanth Swaminathan 	      /* If we read past the last core register, make sure we
507*1fd5a2e1SPrashanth Swaminathan 		 have not read from the stack before and continue
508*1fd5a2e1SPrashanth Swaminathan 		 reading after regp.  */
509*1fd5a2e1SPrashanth Swaminathan 	      if (regp > eo_regp)
510*1fd5a2e1SPrashanth Swaminathan 		{
511*1fd5a2e1SPrashanth Swaminathan 		  FFI_ASSERT (!stack_used);
512*1fd5a2e1SPrashanth Swaminathan 		  argp = regp;
513*1fd5a2e1SPrashanth Swaminathan 		}
514*1fd5a2e1SPrashanth Swaminathan 	      if (regp >= eo_regp)
515*1fd5a2e1SPrashanth Swaminathan 		{
516*1fd5a2e1SPrashanth Swaminathan 		  done_with_regs = 1;
517*1fd5a2e1SPrashanth Swaminathan 		  stack_used = 1;
518*1fd5a2e1SPrashanth Swaminathan 		}
519*1fd5a2e1SPrashanth Swaminathan 	      continue;
520*1fd5a2e1SPrashanth Swaminathan 	    }
521*1fd5a2e1SPrashanth Swaminathan 	}
522*1fd5a2e1SPrashanth Swaminathan 
523*1fd5a2e1SPrashanth Swaminathan       stack_used = 1;
524*1fd5a2e1SPrashanth Swaminathan       argp = ffi_align (ty, argp);
525*1fd5a2e1SPrashanth Swaminathan       avalue[i] = (void *) argp;
526*1fd5a2e1SPrashanth Swaminathan       argp += z;
527*1fd5a2e1SPrashanth Swaminathan     }
528*1fd5a2e1SPrashanth Swaminathan 
529*1fd5a2e1SPrashanth Swaminathan   return rvalue;
530*1fd5a2e1SPrashanth Swaminathan }
531*1fd5a2e1SPrashanth Swaminathan 
532*1fd5a2e1SPrashanth Swaminathan struct closure_frame
533*1fd5a2e1SPrashanth Swaminathan {
534*1fd5a2e1SPrashanth Swaminathan   char vfp_space[8*8] __attribute__((aligned(8)));
535*1fd5a2e1SPrashanth Swaminathan   char result[8*4];
536*1fd5a2e1SPrashanth Swaminathan   char argp[];
537*1fd5a2e1SPrashanth Swaminathan };
538*1fd5a2e1SPrashanth Swaminathan 
539*1fd5a2e1SPrashanth Swaminathan int FFI_HIDDEN
ffi_closure_inner_SYSV(ffi_cif * cif,void (* fun)(ffi_cif *,void *,void **,void *),void * user_data,struct closure_frame * frame)540*1fd5a2e1SPrashanth Swaminathan ffi_closure_inner_SYSV (ffi_cif *cif,
541*1fd5a2e1SPrashanth Swaminathan 		        void (*fun) (ffi_cif *, void *, void **, void *),
542*1fd5a2e1SPrashanth Swaminathan 		        void *user_data,
543*1fd5a2e1SPrashanth Swaminathan 		        struct closure_frame *frame)
544*1fd5a2e1SPrashanth Swaminathan {
545*1fd5a2e1SPrashanth Swaminathan   void **avalue = (void **) alloca (cif->nargs * sizeof (void *));
546*1fd5a2e1SPrashanth Swaminathan   void *rvalue = ffi_prep_incoming_args_SYSV (cif, frame->result,
547*1fd5a2e1SPrashanth Swaminathan 					      frame->argp, avalue);
548*1fd5a2e1SPrashanth Swaminathan   fun (cif, rvalue, avalue, user_data);
549*1fd5a2e1SPrashanth Swaminathan   return cif->flags;
550*1fd5a2e1SPrashanth Swaminathan }
551*1fd5a2e1SPrashanth Swaminathan 
552*1fd5a2e1SPrashanth Swaminathan int FFI_HIDDEN
ffi_closure_inner_VFP(ffi_cif * cif,void (* fun)(ffi_cif *,void *,void **,void *),void * user_data,struct closure_frame * frame)553*1fd5a2e1SPrashanth Swaminathan ffi_closure_inner_VFP (ffi_cif *cif,
554*1fd5a2e1SPrashanth Swaminathan 		       void (*fun) (ffi_cif *, void *, void **, void *),
555*1fd5a2e1SPrashanth Swaminathan 		       void *user_data,
556*1fd5a2e1SPrashanth Swaminathan 		       struct closure_frame *frame)
557*1fd5a2e1SPrashanth Swaminathan {
558*1fd5a2e1SPrashanth Swaminathan   void **avalue = (void **) alloca (cif->nargs * sizeof (void *));
559*1fd5a2e1SPrashanth Swaminathan   void *rvalue = ffi_prep_incoming_args_VFP (cif, frame->result, frame->argp,
560*1fd5a2e1SPrashanth Swaminathan 					     frame->vfp_space, avalue);
561*1fd5a2e1SPrashanth Swaminathan   fun (cif, rvalue, avalue, user_data);
562*1fd5a2e1SPrashanth Swaminathan   return cif->flags;
563*1fd5a2e1SPrashanth Swaminathan }
564*1fd5a2e1SPrashanth Swaminathan 
565*1fd5a2e1SPrashanth Swaminathan void ffi_closure_SYSV (void) FFI_HIDDEN;
566*1fd5a2e1SPrashanth Swaminathan void ffi_closure_VFP (void) FFI_HIDDEN;
567*1fd5a2e1SPrashanth Swaminathan void ffi_go_closure_SYSV (void) FFI_HIDDEN;
568*1fd5a2e1SPrashanth Swaminathan void ffi_go_closure_VFP (void) FFI_HIDDEN;
569*1fd5a2e1SPrashanth Swaminathan 
570*1fd5a2e1SPrashanth Swaminathan /* the cif must already be prep'ed */
571*1fd5a2e1SPrashanth Swaminathan 
572*1fd5a2e1SPrashanth Swaminathan ffi_status
ffi_prep_closure_loc(ffi_closure * closure,ffi_cif * cif,void (* fun)(ffi_cif *,void *,void **,void *),void * user_data,void * codeloc)573*1fd5a2e1SPrashanth Swaminathan ffi_prep_closure_loc (ffi_closure * closure,
574*1fd5a2e1SPrashanth Swaminathan 		      ffi_cif * cif,
575*1fd5a2e1SPrashanth Swaminathan 		      void (*fun) (ffi_cif *, void *, void **, void *),
576*1fd5a2e1SPrashanth Swaminathan 		      void *user_data, void *codeloc)
577*1fd5a2e1SPrashanth Swaminathan {
578*1fd5a2e1SPrashanth Swaminathan   void (*closure_func) (void) = ffi_closure_SYSV;
579*1fd5a2e1SPrashanth Swaminathan 
580*1fd5a2e1SPrashanth Swaminathan   if (cif->abi == FFI_VFP)
581*1fd5a2e1SPrashanth Swaminathan     {
582*1fd5a2e1SPrashanth Swaminathan       /* We only need take the vfp path if there are vfp arguments.  */
583*1fd5a2e1SPrashanth Swaminathan       if (cif->vfp_used)
584*1fd5a2e1SPrashanth Swaminathan 	closure_func = ffi_closure_VFP;
585*1fd5a2e1SPrashanth Swaminathan     }
586*1fd5a2e1SPrashanth Swaminathan   else if (cif->abi != FFI_SYSV)
587*1fd5a2e1SPrashanth Swaminathan     return FFI_BAD_ABI;
588*1fd5a2e1SPrashanth Swaminathan 
589*1fd5a2e1SPrashanth Swaminathan #if FFI_EXEC_TRAMPOLINE_TABLE
590*1fd5a2e1SPrashanth Swaminathan   void **config = (void **)((uint8_t *)codeloc - PAGE_MAX_SIZE);
591*1fd5a2e1SPrashanth Swaminathan   config[0] = closure;
592*1fd5a2e1SPrashanth Swaminathan   config[1] = closure_func;
593*1fd5a2e1SPrashanth Swaminathan #else
594*1fd5a2e1SPrashanth Swaminathan 
595*1fd5a2e1SPrashanth Swaminathan #ifndef _M_ARM
596*1fd5a2e1SPrashanth Swaminathan   memcpy(closure->tramp, ffi_arm_trampoline, 8);
597*1fd5a2e1SPrashanth Swaminathan #else
598*1fd5a2e1SPrashanth Swaminathan   // cast away function type so MSVC doesn't set the lower bit of the function pointer
599*1fd5a2e1SPrashanth Swaminathan   memcpy(closure->tramp, (void*)((uintptr_t)ffi_arm_trampoline & 0xFFFFFFFE), FFI_TRAMPOLINE_CLOSURE_OFFSET);
600*1fd5a2e1SPrashanth Swaminathan #endif
601*1fd5a2e1SPrashanth Swaminathan 
602*1fd5a2e1SPrashanth Swaminathan #if defined (__QNX__)
603*1fd5a2e1SPrashanth Swaminathan   msync(closure->tramp, 8, 0x1000000);	/* clear data map */
604*1fd5a2e1SPrashanth Swaminathan   msync(codeloc, 8, 0x1000000);	/* clear insn map */
605*1fd5a2e1SPrashanth Swaminathan #elif defined(_MSC_VER)
606*1fd5a2e1SPrashanth Swaminathan   FlushInstructionCache(GetCurrentProcess(), closure->tramp, FFI_TRAMPOLINE_SIZE);
607*1fd5a2e1SPrashanth Swaminathan #else
608*1fd5a2e1SPrashanth Swaminathan   __clear_cache(closure->tramp, closure->tramp + 8);	/* clear data map */
609*1fd5a2e1SPrashanth Swaminathan   __clear_cache(codeloc, codeloc + 8);			/* clear insn map */
610*1fd5a2e1SPrashanth Swaminathan #endif
611*1fd5a2e1SPrashanth Swaminathan #ifdef _M_ARM
612*1fd5a2e1SPrashanth Swaminathan   *(void(**)(void))(closure->tramp + FFI_TRAMPOLINE_CLOSURE_FUNCTION) = closure_func;
613*1fd5a2e1SPrashanth Swaminathan #else
614*1fd5a2e1SPrashanth Swaminathan   *(void (**)(void))(closure->tramp + 8) = closure_func;
615*1fd5a2e1SPrashanth Swaminathan #endif
616*1fd5a2e1SPrashanth Swaminathan #endif
617*1fd5a2e1SPrashanth Swaminathan 
618*1fd5a2e1SPrashanth Swaminathan   closure->cif = cif;
619*1fd5a2e1SPrashanth Swaminathan   closure->fun = fun;
620*1fd5a2e1SPrashanth Swaminathan   closure->user_data = user_data;
621*1fd5a2e1SPrashanth Swaminathan 
622*1fd5a2e1SPrashanth Swaminathan   return FFI_OK;
623*1fd5a2e1SPrashanth Swaminathan }
624*1fd5a2e1SPrashanth Swaminathan 
625*1fd5a2e1SPrashanth Swaminathan ffi_status
ffi_prep_go_closure(ffi_go_closure * closure,ffi_cif * cif,void (* fun)(ffi_cif *,void *,void **,void *))626*1fd5a2e1SPrashanth Swaminathan ffi_prep_go_closure (ffi_go_closure *closure, ffi_cif *cif,
627*1fd5a2e1SPrashanth Swaminathan 		     void (*fun) (ffi_cif *, void *, void **, void *))
628*1fd5a2e1SPrashanth Swaminathan {
629*1fd5a2e1SPrashanth Swaminathan   void (*closure_func) (void) = ffi_go_closure_SYSV;
630*1fd5a2e1SPrashanth Swaminathan 
631*1fd5a2e1SPrashanth Swaminathan   if (cif->abi == FFI_VFP)
632*1fd5a2e1SPrashanth Swaminathan     {
633*1fd5a2e1SPrashanth Swaminathan       /* We only need take the vfp path if there are vfp arguments.  */
634*1fd5a2e1SPrashanth Swaminathan       if (cif->vfp_used)
635*1fd5a2e1SPrashanth Swaminathan 	closure_func = ffi_go_closure_VFP;
636*1fd5a2e1SPrashanth Swaminathan     }
637*1fd5a2e1SPrashanth Swaminathan   else if (cif->abi != FFI_SYSV)
638*1fd5a2e1SPrashanth Swaminathan     return FFI_BAD_ABI;
639*1fd5a2e1SPrashanth Swaminathan 
640*1fd5a2e1SPrashanth Swaminathan   closure->tramp = closure_func;
641*1fd5a2e1SPrashanth Swaminathan   closure->cif = cif;
642*1fd5a2e1SPrashanth Swaminathan   closure->fun = fun;
643*1fd5a2e1SPrashanth Swaminathan 
644*1fd5a2e1SPrashanth Swaminathan   return FFI_OK;
645*1fd5a2e1SPrashanth Swaminathan }
646*1fd5a2e1SPrashanth Swaminathan 
647*1fd5a2e1SPrashanth Swaminathan /* Below are routines for VFP hard-float support. */
648*1fd5a2e1SPrashanth Swaminathan 
649*1fd5a2e1SPrashanth Swaminathan /* A subroutine of vfp_type_p.  Given a structure type, return the type code
650*1fd5a2e1SPrashanth Swaminathan    of the first non-structure element.  Recurse for structure elements.
651*1fd5a2e1SPrashanth Swaminathan    Return -1 if the structure is in fact empty, i.e. no nested elements.  */
652*1fd5a2e1SPrashanth Swaminathan 
653*1fd5a2e1SPrashanth Swaminathan static int
is_hfa0(const ffi_type * ty)654*1fd5a2e1SPrashanth Swaminathan is_hfa0 (const ffi_type *ty)
655*1fd5a2e1SPrashanth Swaminathan {
656*1fd5a2e1SPrashanth Swaminathan   ffi_type **elements = ty->elements;
657*1fd5a2e1SPrashanth Swaminathan   int i, ret = -1;
658*1fd5a2e1SPrashanth Swaminathan 
659*1fd5a2e1SPrashanth Swaminathan   if (elements != NULL)
660*1fd5a2e1SPrashanth Swaminathan     for (i = 0; elements[i]; ++i)
661*1fd5a2e1SPrashanth Swaminathan       {
662*1fd5a2e1SPrashanth Swaminathan         ret = elements[i]->type;
663*1fd5a2e1SPrashanth Swaminathan         if (ret == FFI_TYPE_STRUCT || ret == FFI_TYPE_COMPLEX)
664*1fd5a2e1SPrashanth Swaminathan           {
665*1fd5a2e1SPrashanth Swaminathan             ret = is_hfa0 (elements[i]);
666*1fd5a2e1SPrashanth Swaminathan             if (ret < 0)
667*1fd5a2e1SPrashanth Swaminathan               continue;
668*1fd5a2e1SPrashanth Swaminathan           }
669*1fd5a2e1SPrashanth Swaminathan         break;
670*1fd5a2e1SPrashanth Swaminathan       }
671*1fd5a2e1SPrashanth Swaminathan 
672*1fd5a2e1SPrashanth Swaminathan   return ret;
673*1fd5a2e1SPrashanth Swaminathan }
674*1fd5a2e1SPrashanth Swaminathan 
675*1fd5a2e1SPrashanth Swaminathan /* A subroutine of vfp_type_p.  Given a structure type, return true if all
676*1fd5a2e1SPrashanth Swaminathan    of the non-structure elements are the same as CANDIDATE.  */
677*1fd5a2e1SPrashanth Swaminathan 
678*1fd5a2e1SPrashanth Swaminathan static int
is_hfa1(const ffi_type * ty,int candidate)679*1fd5a2e1SPrashanth Swaminathan is_hfa1 (const ffi_type *ty, int candidate)
680*1fd5a2e1SPrashanth Swaminathan {
681*1fd5a2e1SPrashanth Swaminathan   ffi_type **elements = ty->elements;
682*1fd5a2e1SPrashanth Swaminathan   int i;
683*1fd5a2e1SPrashanth Swaminathan 
684*1fd5a2e1SPrashanth Swaminathan   if (elements != NULL)
685*1fd5a2e1SPrashanth Swaminathan     for (i = 0; elements[i]; ++i)
686*1fd5a2e1SPrashanth Swaminathan       {
687*1fd5a2e1SPrashanth Swaminathan         int t = elements[i]->type;
688*1fd5a2e1SPrashanth Swaminathan         if (t == FFI_TYPE_STRUCT || t == FFI_TYPE_COMPLEX)
689*1fd5a2e1SPrashanth Swaminathan           {
690*1fd5a2e1SPrashanth Swaminathan             if (!is_hfa1 (elements[i], candidate))
691*1fd5a2e1SPrashanth Swaminathan               return 0;
692*1fd5a2e1SPrashanth Swaminathan           }
693*1fd5a2e1SPrashanth Swaminathan         else if (t != candidate)
694*1fd5a2e1SPrashanth Swaminathan           return 0;
695*1fd5a2e1SPrashanth Swaminathan       }
696*1fd5a2e1SPrashanth Swaminathan 
697*1fd5a2e1SPrashanth Swaminathan   return 1;
698*1fd5a2e1SPrashanth Swaminathan }
699*1fd5a2e1SPrashanth Swaminathan 
700*1fd5a2e1SPrashanth Swaminathan /* Determine if TY is an homogenous floating point aggregate (HFA).
701*1fd5a2e1SPrashanth Swaminathan    That is, a structure consisting of 1 to 4 members of all the same type,
702*1fd5a2e1SPrashanth Swaminathan    where that type is a floating point scalar.
703*1fd5a2e1SPrashanth Swaminathan 
704*1fd5a2e1SPrashanth Swaminathan    Returns non-zero iff TY is an HFA.  The result is an encoded value where
705*1fd5a2e1SPrashanth Swaminathan    bits 0-7 contain the type code, and bits 8-10 contain the element count.  */
706*1fd5a2e1SPrashanth Swaminathan 
707*1fd5a2e1SPrashanth Swaminathan static int
vfp_type_p(const ffi_type * ty)708*1fd5a2e1SPrashanth Swaminathan vfp_type_p (const ffi_type *ty)
709*1fd5a2e1SPrashanth Swaminathan {
710*1fd5a2e1SPrashanth Swaminathan   ffi_type **elements;
711*1fd5a2e1SPrashanth Swaminathan   int candidate, i;
712*1fd5a2e1SPrashanth Swaminathan   size_t size, ele_count;
713*1fd5a2e1SPrashanth Swaminathan 
714*1fd5a2e1SPrashanth Swaminathan   /* Quickest tests first.  */
715*1fd5a2e1SPrashanth Swaminathan   candidate = ty->type;
716*1fd5a2e1SPrashanth Swaminathan   switch (ty->type)
717*1fd5a2e1SPrashanth Swaminathan     {
718*1fd5a2e1SPrashanth Swaminathan     default:
719*1fd5a2e1SPrashanth Swaminathan       return 0;
720*1fd5a2e1SPrashanth Swaminathan     case FFI_TYPE_FLOAT:
721*1fd5a2e1SPrashanth Swaminathan     case FFI_TYPE_DOUBLE:
722*1fd5a2e1SPrashanth Swaminathan       ele_count = 1;
723*1fd5a2e1SPrashanth Swaminathan       goto done;
724*1fd5a2e1SPrashanth Swaminathan     case FFI_TYPE_COMPLEX:
725*1fd5a2e1SPrashanth Swaminathan       candidate = ty->elements[0]->type;
726*1fd5a2e1SPrashanth Swaminathan       if (candidate != FFI_TYPE_FLOAT && candidate != FFI_TYPE_DOUBLE)
727*1fd5a2e1SPrashanth Swaminathan 	return 0;
728*1fd5a2e1SPrashanth Swaminathan       ele_count = 2;
729*1fd5a2e1SPrashanth Swaminathan       goto done;
730*1fd5a2e1SPrashanth Swaminathan     case FFI_TYPE_STRUCT:
731*1fd5a2e1SPrashanth Swaminathan       break;
732*1fd5a2e1SPrashanth Swaminathan     }
733*1fd5a2e1SPrashanth Swaminathan 
734*1fd5a2e1SPrashanth Swaminathan   /* No HFA types are smaller than 4 bytes, or larger than 32 bytes.  */
735*1fd5a2e1SPrashanth Swaminathan   size = ty->size;
736*1fd5a2e1SPrashanth Swaminathan   if (size < 4 || size > 32)
737*1fd5a2e1SPrashanth Swaminathan     return 0;
738*1fd5a2e1SPrashanth Swaminathan 
739*1fd5a2e1SPrashanth Swaminathan   /* Find the type of the first non-structure member.  */
740*1fd5a2e1SPrashanth Swaminathan   elements = ty->elements;
741*1fd5a2e1SPrashanth Swaminathan   candidate = elements[0]->type;
742*1fd5a2e1SPrashanth Swaminathan   if (candidate == FFI_TYPE_STRUCT || candidate == FFI_TYPE_COMPLEX)
743*1fd5a2e1SPrashanth Swaminathan     {
744*1fd5a2e1SPrashanth Swaminathan       for (i = 0; ; ++i)
745*1fd5a2e1SPrashanth Swaminathan         {
746*1fd5a2e1SPrashanth Swaminathan           candidate = is_hfa0 (elements[i]);
747*1fd5a2e1SPrashanth Swaminathan           if (candidate >= 0)
748*1fd5a2e1SPrashanth Swaminathan             break;
749*1fd5a2e1SPrashanth Swaminathan         }
750*1fd5a2e1SPrashanth Swaminathan     }
751*1fd5a2e1SPrashanth Swaminathan 
752*1fd5a2e1SPrashanth Swaminathan   /* If the first member is not a floating point type, it's not an HFA.
753*1fd5a2e1SPrashanth Swaminathan      Also quickly re-check the size of the structure.  */
754*1fd5a2e1SPrashanth Swaminathan   switch (candidate)
755*1fd5a2e1SPrashanth Swaminathan     {
756*1fd5a2e1SPrashanth Swaminathan     case FFI_TYPE_FLOAT:
757*1fd5a2e1SPrashanth Swaminathan       ele_count = size / sizeof(float);
758*1fd5a2e1SPrashanth Swaminathan       if (size != ele_count * sizeof(float))
759*1fd5a2e1SPrashanth Swaminathan         return 0;
760*1fd5a2e1SPrashanth Swaminathan       break;
761*1fd5a2e1SPrashanth Swaminathan     case FFI_TYPE_DOUBLE:
762*1fd5a2e1SPrashanth Swaminathan       ele_count = size / sizeof(double);
763*1fd5a2e1SPrashanth Swaminathan       if (size != ele_count * sizeof(double))
764*1fd5a2e1SPrashanth Swaminathan         return 0;
765*1fd5a2e1SPrashanth Swaminathan       break;
766*1fd5a2e1SPrashanth Swaminathan     default:
767*1fd5a2e1SPrashanth Swaminathan       return 0;
768*1fd5a2e1SPrashanth Swaminathan     }
769*1fd5a2e1SPrashanth Swaminathan   if (ele_count > 4)
770*1fd5a2e1SPrashanth Swaminathan     return 0;
771*1fd5a2e1SPrashanth Swaminathan 
772*1fd5a2e1SPrashanth Swaminathan   /* Finally, make sure that all scalar elements are the same type.  */
773*1fd5a2e1SPrashanth Swaminathan   for (i = 0; elements[i]; ++i)
774*1fd5a2e1SPrashanth Swaminathan     {
775*1fd5a2e1SPrashanth Swaminathan       int t = elements[i]->type;
776*1fd5a2e1SPrashanth Swaminathan       if (t == FFI_TYPE_STRUCT || t == FFI_TYPE_COMPLEX)
777*1fd5a2e1SPrashanth Swaminathan         {
778*1fd5a2e1SPrashanth Swaminathan           if (!is_hfa1 (elements[i], candidate))
779*1fd5a2e1SPrashanth Swaminathan             return 0;
780*1fd5a2e1SPrashanth Swaminathan         }
781*1fd5a2e1SPrashanth Swaminathan       else if (t != candidate)
782*1fd5a2e1SPrashanth Swaminathan         return 0;
783*1fd5a2e1SPrashanth Swaminathan     }
784*1fd5a2e1SPrashanth Swaminathan 
785*1fd5a2e1SPrashanth Swaminathan   /* All tests succeeded.  Encode the result.  */
786*1fd5a2e1SPrashanth Swaminathan  done:
787*1fd5a2e1SPrashanth Swaminathan   return (ele_count << 8) | candidate;
788*1fd5a2e1SPrashanth Swaminathan }
789*1fd5a2e1SPrashanth Swaminathan 
790*1fd5a2e1SPrashanth Swaminathan static int
place_vfp_arg(ffi_cif * cif,int h)791*1fd5a2e1SPrashanth Swaminathan place_vfp_arg (ffi_cif *cif, int h)
792*1fd5a2e1SPrashanth Swaminathan {
793*1fd5a2e1SPrashanth Swaminathan   unsigned short reg = cif->vfp_reg_free;
794*1fd5a2e1SPrashanth Swaminathan   int align = 1, nregs = h >> 8;
795*1fd5a2e1SPrashanth Swaminathan 
796*1fd5a2e1SPrashanth Swaminathan   if ((h & 0xff) == FFI_TYPE_DOUBLE)
797*1fd5a2e1SPrashanth Swaminathan     align = 2, nregs *= 2;
798*1fd5a2e1SPrashanth Swaminathan 
799*1fd5a2e1SPrashanth Swaminathan   /* Align register number. */
800*1fd5a2e1SPrashanth Swaminathan   if ((reg & 1) && align == 2)
801*1fd5a2e1SPrashanth Swaminathan     reg++;
802*1fd5a2e1SPrashanth Swaminathan 
803*1fd5a2e1SPrashanth Swaminathan   while (reg + nregs <= 16)
804*1fd5a2e1SPrashanth Swaminathan     {
805*1fd5a2e1SPrashanth Swaminathan       int s, new_used = 0;
806*1fd5a2e1SPrashanth Swaminathan       for (s = reg; s < reg + nregs; s++)
807*1fd5a2e1SPrashanth Swaminathan 	{
808*1fd5a2e1SPrashanth Swaminathan 	  new_used |= (1 << s);
809*1fd5a2e1SPrashanth Swaminathan 	  if (cif->vfp_used & (1 << s))
810*1fd5a2e1SPrashanth Swaminathan 	    {
811*1fd5a2e1SPrashanth Swaminathan 	      reg += align;
812*1fd5a2e1SPrashanth Swaminathan 	      goto next_reg;
813*1fd5a2e1SPrashanth Swaminathan 	    }
814*1fd5a2e1SPrashanth Swaminathan 	}
815*1fd5a2e1SPrashanth Swaminathan       /* Found regs to allocate. */
816*1fd5a2e1SPrashanth Swaminathan       cif->vfp_used |= new_used;
817*1fd5a2e1SPrashanth Swaminathan       cif->vfp_args[cif->vfp_nargs++] = (signed char)reg;
818*1fd5a2e1SPrashanth Swaminathan 
819*1fd5a2e1SPrashanth Swaminathan       /* Update vfp_reg_free. */
820*1fd5a2e1SPrashanth Swaminathan       if (cif->vfp_used & (1 << cif->vfp_reg_free))
821*1fd5a2e1SPrashanth Swaminathan 	{
822*1fd5a2e1SPrashanth Swaminathan 	  reg += nregs;
823*1fd5a2e1SPrashanth Swaminathan 	  while (cif->vfp_used & (1 << reg))
824*1fd5a2e1SPrashanth Swaminathan 	    reg += 1;
825*1fd5a2e1SPrashanth Swaminathan 	  cif->vfp_reg_free = reg;
826*1fd5a2e1SPrashanth Swaminathan 	}
827*1fd5a2e1SPrashanth Swaminathan       return 0;
828*1fd5a2e1SPrashanth Swaminathan     next_reg:;
829*1fd5a2e1SPrashanth Swaminathan     }
830*1fd5a2e1SPrashanth Swaminathan   // done, mark all regs as used
831*1fd5a2e1SPrashanth Swaminathan   cif->vfp_reg_free = 16;
832*1fd5a2e1SPrashanth Swaminathan   cif->vfp_used = 0xFFFF;
833*1fd5a2e1SPrashanth Swaminathan   return 1;
834*1fd5a2e1SPrashanth Swaminathan }
835*1fd5a2e1SPrashanth Swaminathan 
836*1fd5a2e1SPrashanth Swaminathan static void
layout_vfp_args(ffi_cif * cif)837*1fd5a2e1SPrashanth Swaminathan layout_vfp_args (ffi_cif * cif)
838*1fd5a2e1SPrashanth Swaminathan {
839*1fd5a2e1SPrashanth Swaminathan   unsigned int i;
840*1fd5a2e1SPrashanth Swaminathan   /* Init VFP fields */
841*1fd5a2e1SPrashanth Swaminathan   cif->vfp_used = 0;
842*1fd5a2e1SPrashanth Swaminathan   cif->vfp_nargs = 0;
843*1fd5a2e1SPrashanth Swaminathan   cif->vfp_reg_free = 0;
844*1fd5a2e1SPrashanth Swaminathan   memset (cif->vfp_args, -1, 16);	/* Init to -1. */
845*1fd5a2e1SPrashanth Swaminathan 
846*1fd5a2e1SPrashanth Swaminathan   for (i = 0; i < cif->nargs; i++)
847*1fd5a2e1SPrashanth Swaminathan     {
848*1fd5a2e1SPrashanth Swaminathan       int h = vfp_type_p (cif->arg_types[i]);
849*1fd5a2e1SPrashanth Swaminathan       if (h && place_vfp_arg (cif, h) == 1)
850*1fd5a2e1SPrashanth Swaminathan 	break;
851*1fd5a2e1SPrashanth Swaminathan     }
852*1fd5a2e1SPrashanth Swaminathan }
853*1fd5a2e1SPrashanth Swaminathan 
854*1fd5a2e1SPrashanth Swaminathan #endif /* __arm__ or _M_ARM */
855