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