xref: /aosp_15_r20/external/libffi/src/aarch64/ffi.c (revision 1fd5a2e1d639cd1ddf29dd0c484c123bbd850c21)
1*1fd5a2e1SPrashanth Swaminathan /* Copyright (c) 2009, 2010, 2011, 2012 ARM Ltd.
2*1fd5a2e1SPrashanth Swaminathan 
3*1fd5a2e1SPrashanth Swaminathan Permission is hereby granted, free of charge, to any person obtaining
4*1fd5a2e1SPrashanth Swaminathan a copy of this software and associated documentation files (the
5*1fd5a2e1SPrashanth Swaminathan ``Software''), to deal in the Software without restriction, including
6*1fd5a2e1SPrashanth Swaminathan without limitation the rights to use, copy, modify, merge, publish,
7*1fd5a2e1SPrashanth Swaminathan distribute, sublicense, and/or sell copies of the Software, and to
8*1fd5a2e1SPrashanth Swaminathan permit persons to whom the Software is furnished to do so, subject to
9*1fd5a2e1SPrashanth Swaminathan the following conditions:
10*1fd5a2e1SPrashanth Swaminathan 
11*1fd5a2e1SPrashanth Swaminathan The above copyright notice and this permission notice shall be
12*1fd5a2e1SPrashanth Swaminathan included in all copies or substantial portions of the Software.
13*1fd5a2e1SPrashanth Swaminathan 
14*1fd5a2e1SPrashanth Swaminathan THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND,
15*1fd5a2e1SPrashanth Swaminathan EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16*1fd5a2e1SPrashanth Swaminathan MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
17*1fd5a2e1SPrashanth Swaminathan IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
18*1fd5a2e1SPrashanth Swaminathan CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
19*1fd5a2e1SPrashanth Swaminathan TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
20*1fd5a2e1SPrashanth Swaminathan SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.  */
21*1fd5a2e1SPrashanth Swaminathan 
22*1fd5a2e1SPrashanth Swaminathan #if defined(__aarch64__) || defined(__arm64__)|| defined (_M_ARM64)
23*1fd5a2e1SPrashanth Swaminathan #include <stdio.h>
24*1fd5a2e1SPrashanth Swaminathan #include <stdlib.h>
25*1fd5a2e1SPrashanth Swaminathan #include <stdint.h>
26*1fd5a2e1SPrashanth Swaminathan #include <fficonfig.h>
27*1fd5a2e1SPrashanth Swaminathan #include <ffi.h>
28*1fd5a2e1SPrashanth Swaminathan #include <ffi_common.h>
29*1fd5a2e1SPrashanth Swaminathan #include "internal.h"
30*1fd5a2e1SPrashanth Swaminathan #ifdef _M_ARM64
31*1fd5a2e1SPrashanth Swaminathan #include <windows.h> /* FlushInstructionCache */
32*1fd5a2e1SPrashanth Swaminathan #endif
33*1fd5a2e1SPrashanth Swaminathan 
34*1fd5a2e1SPrashanth Swaminathan /* Force FFI_TYPE_LONGDOUBLE to be different than FFI_TYPE_DOUBLE;
35*1fd5a2e1SPrashanth Swaminathan    all further uses in this file will refer to the 128-bit type.  */
36*1fd5a2e1SPrashanth Swaminathan #if FFI_TYPE_DOUBLE != FFI_TYPE_LONGDOUBLE
37*1fd5a2e1SPrashanth Swaminathan # if FFI_TYPE_LONGDOUBLE != 4
38*1fd5a2e1SPrashanth Swaminathan #  error FFI_TYPE_LONGDOUBLE out of date
39*1fd5a2e1SPrashanth Swaminathan # endif
40*1fd5a2e1SPrashanth Swaminathan #else
41*1fd5a2e1SPrashanth Swaminathan # undef FFI_TYPE_LONGDOUBLE
42*1fd5a2e1SPrashanth Swaminathan # define FFI_TYPE_LONGDOUBLE 4
43*1fd5a2e1SPrashanth Swaminathan #endif
44*1fd5a2e1SPrashanth Swaminathan 
45*1fd5a2e1SPrashanth Swaminathan union _d
46*1fd5a2e1SPrashanth Swaminathan {
47*1fd5a2e1SPrashanth Swaminathan   UINT64 d;
48*1fd5a2e1SPrashanth Swaminathan   UINT32 s[2];
49*1fd5a2e1SPrashanth Swaminathan };
50*1fd5a2e1SPrashanth Swaminathan 
51*1fd5a2e1SPrashanth Swaminathan struct _v
52*1fd5a2e1SPrashanth Swaminathan {
53*1fd5a2e1SPrashanth Swaminathan   union _d d[2] __attribute__((aligned(16)));
54*1fd5a2e1SPrashanth Swaminathan };
55*1fd5a2e1SPrashanth Swaminathan 
56*1fd5a2e1SPrashanth Swaminathan struct call_context
57*1fd5a2e1SPrashanth Swaminathan {
58*1fd5a2e1SPrashanth Swaminathan   struct _v v[N_V_ARG_REG];
59*1fd5a2e1SPrashanth Swaminathan   UINT64 x[N_X_ARG_REG];
60*1fd5a2e1SPrashanth Swaminathan };
61*1fd5a2e1SPrashanth Swaminathan 
62*1fd5a2e1SPrashanth Swaminathan #if FFI_EXEC_TRAMPOLINE_TABLE
63*1fd5a2e1SPrashanth Swaminathan 
64*1fd5a2e1SPrashanth Swaminathan #ifdef __MACH__
65*1fd5a2e1SPrashanth Swaminathan #include <mach/vm_param.h>
66*1fd5a2e1SPrashanth Swaminathan #endif
67*1fd5a2e1SPrashanth Swaminathan 
68*1fd5a2e1SPrashanth Swaminathan #else
69*1fd5a2e1SPrashanth Swaminathan 
70*1fd5a2e1SPrashanth Swaminathan #if defined (__clang__) && defined (__APPLE__)
71*1fd5a2e1SPrashanth Swaminathan extern void sys_icache_invalidate (void *start, size_t len);
72*1fd5a2e1SPrashanth Swaminathan #endif
73*1fd5a2e1SPrashanth Swaminathan 
74*1fd5a2e1SPrashanth Swaminathan static inline void
ffi_clear_cache(void * start,void * end)75*1fd5a2e1SPrashanth Swaminathan ffi_clear_cache (void *start, void *end)
76*1fd5a2e1SPrashanth Swaminathan {
77*1fd5a2e1SPrashanth Swaminathan #if defined (__clang__) && defined (__APPLE__)
78*1fd5a2e1SPrashanth Swaminathan   sys_icache_invalidate (start, (char *)end - (char *)start);
79*1fd5a2e1SPrashanth Swaminathan #elif defined (__GNUC__)
80*1fd5a2e1SPrashanth Swaminathan   __builtin___clear_cache (start, end);
81*1fd5a2e1SPrashanth Swaminathan #elif defined (_M_ARM64)
82*1fd5a2e1SPrashanth Swaminathan   FlushInstructionCache(GetCurrentProcess(), start, (char*)end - (char*)start);
83*1fd5a2e1SPrashanth Swaminathan #else
84*1fd5a2e1SPrashanth Swaminathan #error "Missing builtin to flush instruction cache"
85*1fd5a2e1SPrashanth Swaminathan #endif
86*1fd5a2e1SPrashanth Swaminathan }
87*1fd5a2e1SPrashanth Swaminathan 
88*1fd5a2e1SPrashanth Swaminathan #endif
89*1fd5a2e1SPrashanth Swaminathan 
90*1fd5a2e1SPrashanth Swaminathan /* A subroutine of is_vfp_type.  Given a structure type, return the type code
91*1fd5a2e1SPrashanth Swaminathan    of the first non-structure element.  Recurse for structure elements.
92*1fd5a2e1SPrashanth Swaminathan    Return -1 if the structure is in fact empty, i.e. no nested elements.  */
93*1fd5a2e1SPrashanth Swaminathan 
94*1fd5a2e1SPrashanth Swaminathan static int
is_hfa0(const ffi_type * ty)95*1fd5a2e1SPrashanth Swaminathan is_hfa0 (const ffi_type *ty)
96*1fd5a2e1SPrashanth Swaminathan {
97*1fd5a2e1SPrashanth Swaminathan   ffi_type **elements = ty->elements;
98*1fd5a2e1SPrashanth Swaminathan   int i, ret = -1;
99*1fd5a2e1SPrashanth Swaminathan 
100*1fd5a2e1SPrashanth Swaminathan   if (elements != NULL)
101*1fd5a2e1SPrashanth Swaminathan     for (i = 0; elements[i]; ++i)
102*1fd5a2e1SPrashanth Swaminathan       {
103*1fd5a2e1SPrashanth Swaminathan         ret = elements[i]->type;
104*1fd5a2e1SPrashanth Swaminathan         if (ret == FFI_TYPE_STRUCT || ret == FFI_TYPE_COMPLEX)
105*1fd5a2e1SPrashanth Swaminathan           {
106*1fd5a2e1SPrashanth Swaminathan             ret = is_hfa0 (elements[i]);
107*1fd5a2e1SPrashanth Swaminathan             if (ret < 0)
108*1fd5a2e1SPrashanth Swaminathan               continue;
109*1fd5a2e1SPrashanth Swaminathan           }
110*1fd5a2e1SPrashanth Swaminathan         break;
111*1fd5a2e1SPrashanth Swaminathan       }
112*1fd5a2e1SPrashanth Swaminathan 
113*1fd5a2e1SPrashanth Swaminathan   return ret;
114*1fd5a2e1SPrashanth Swaminathan }
115*1fd5a2e1SPrashanth Swaminathan 
116*1fd5a2e1SPrashanth Swaminathan /* A subroutine of is_vfp_type.  Given a structure type, return true if all
117*1fd5a2e1SPrashanth Swaminathan    of the non-structure elements are the same as CANDIDATE.  */
118*1fd5a2e1SPrashanth Swaminathan 
119*1fd5a2e1SPrashanth Swaminathan static int
is_hfa1(const ffi_type * ty,int candidate)120*1fd5a2e1SPrashanth Swaminathan is_hfa1 (const ffi_type *ty, int candidate)
121*1fd5a2e1SPrashanth Swaminathan {
122*1fd5a2e1SPrashanth Swaminathan   ffi_type **elements = ty->elements;
123*1fd5a2e1SPrashanth Swaminathan   int i;
124*1fd5a2e1SPrashanth Swaminathan 
125*1fd5a2e1SPrashanth Swaminathan   if (elements != NULL)
126*1fd5a2e1SPrashanth Swaminathan     for (i = 0; elements[i]; ++i)
127*1fd5a2e1SPrashanth Swaminathan       {
128*1fd5a2e1SPrashanth Swaminathan         int t = elements[i]->type;
129*1fd5a2e1SPrashanth Swaminathan         if (t == FFI_TYPE_STRUCT || t == FFI_TYPE_COMPLEX)
130*1fd5a2e1SPrashanth Swaminathan           {
131*1fd5a2e1SPrashanth Swaminathan             if (!is_hfa1 (elements[i], candidate))
132*1fd5a2e1SPrashanth Swaminathan               return 0;
133*1fd5a2e1SPrashanth Swaminathan           }
134*1fd5a2e1SPrashanth Swaminathan         else if (t != candidate)
135*1fd5a2e1SPrashanth Swaminathan           return 0;
136*1fd5a2e1SPrashanth Swaminathan       }
137*1fd5a2e1SPrashanth Swaminathan 
138*1fd5a2e1SPrashanth Swaminathan   return 1;
139*1fd5a2e1SPrashanth Swaminathan }
140*1fd5a2e1SPrashanth Swaminathan 
141*1fd5a2e1SPrashanth Swaminathan /* Determine if TY may be allocated to the FP registers.  This is both an
142*1fd5a2e1SPrashanth Swaminathan    fp scalar type as well as an homogenous floating point aggregate (HFA).
143*1fd5a2e1SPrashanth Swaminathan    That is, a structure consisting of 1 to 4 members of all the same type,
144*1fd5a2e1SPrashanth Swaminathan    where that type is an fp scalar.
145*1fd5a2e1SPrashanth Swaminathan 
146*1fd5a2e1SPrashanth Swaminathan    Returns non-zero iff TY is an HFA.  The result is the AARCH64_RET_*
147*1fd5a2e1SPrashanth Swaminathan    constant for the type.  */
148*1fd5a2e1SPrashanth Swaminathan 
149*1fd5a2e1SPrashanth Swaminathan static int
is_vfp_type(const ffi_type * ty)150*1fd5a2e1SPrashanth Swaminathan is_vfp_type (const ffi_type *ty)
151*1fd5a2e1SPrashanth Swaminathan {
152*1fd5a2e1SPrashanth Swaminathan   ffi_type **elements;
153*1fd5a2e1SPrashanth Swaminathan   int candidate, i;
154*1fd5a2e1SPrashanth Swaminathan   size_t size, ele_count;
155*1fd5a2e1SPrashanth Swaminathan 
156*1fd5a2e1SPrashanth Swaminathan   /* Quickest tests first.  */
157*1fd5a2e1SPrashanth Swaminathan   candidate = ty->type;
158*1fd5a2e1SPrashanth Swaminathan   switch (candidate)
159*1fd5a2e1SPrashanth Swaminathan     {
160*1fd5a2e1SPrashanth Swaminathan     default:
161*1fd5a2e1SPrashanth Swaminathan       return 0;
162*1fd5a2e1SPrashanth Swaminathan     case FFI_TYPE_FLOAT:
163*1fd5a2e1SPrashanth Swaminathan     case FFI_TYPE_DOUBLE:
164*1fd5a2e1SPrashanth Swaminathan     case FFI_TYPE_LONGDOUBLE:
165*1fd5a2e1SPrashanth Swaminathan       ele_count = 1;
166*1fd5a2e1SPrashanth Swaminathan       goto done;
167*1fd5a2e1SPrashanth Swaminathan     case FFI_TYPE_COMPLEX:
168*1fd5a2e1SPrashanth Swaminathan       candidate = ty->elements[0]->type;
169*1fd5a2e1SPrashanth Swaminathan       switch (candidate)
170*1fd5a2e1SPrashanth Swaminathan 	{
171*1fd5a2e1SPrashanth Swaminathan 	case FFI_TYPE_FLOAT:
172*1fd5a2e1SPrashanth Swaminathan 	case FFI_TYPE_DOUBLE:
173*1fd5a2e1SPrashanth Swaminathan 	case FFI_TYPE_LONGDOUBLE:
174*1fd5a2e1SPrashanth Swaminathan 	  ele_count = 2;
175*1fd5a2e1SPrashanth Swaminathan 	  goto done;
176*1fd5a2e1SPrashanth Swaminathan 	}
177*1fd5a2e1SPrashanth Swaminathan       return 0;
178*1fd5a2e1SPrashanth Swaminathan     case FFI_TYPE_STRUCT:
179*1fd5a2e1SPrashanth Swaminathan       break;
180*1fd5a2e1SPrashanth Swaminathan     }
181*1fd5a2e1SPrashanth Swaminathan 
182*1fd5a2e1SPrashanth Swaminathan   /* No HFA types are smaller than 4 bytes, or larger than 64 bytes.  */
183*1fd5a2e1SPrashanth Swaminathan   size = ty->size;
184*1fd5a2e1SPrashanth Swaminathan   if (size < 4 || size > 64)
185*1fd5a2e1SPrashanth Swaminathan     return 0;
186*1fd5a2e1SPrashanth Swaminathan 
187*1fd5a2e1SPrashanth Swaminathan   /* Find the type of the first non-structure member.  */
188*1fd5a2e1SPrashanth Swaminathan   elements = ty->elements;
189*1fd5a2e1SPrashanth Swaminathan   candidate = elements[0]->type;
190*1fd5a2e1SPrashanth Swaminathan   if (candidate == FFI_TYPE_STRUCT || candidate == FFI_TYPE_COMPLEX)
191*1fd5a2e1SPrashanth Swaminathan     {
192*1fd5a2e1SPrashanth Swaminathan       for (i = 0; ; ++i)
193*1fd5a2e1SPrashanth Swaminathan         {
194*1fd5a2e1SPrashanth Swaminathan           candidate = is_hfa0 (elements[i]);
195*1fd5a2e1SPrashanth Swaminathan           if (candidate >= 0)
196*1fd5a2e1SPrashanth Swaminathan             break;
197*1fd5a2e1SPrashanth Swaminathan         }
198*1fd5a2e1SPrashanth Swaminathan     }
199*1fd5a2e1SPrashanth Swaminathan 
200*1fd5a2e1SPrashanth Swaminathan   /* If the first member is not a floating point type, it's not an HFA.
201*1fd5a2e1SPrashanth Swaminathan      Also quickly re-check the size of the structure.  */
202*1fd5a2e1SPrashanth Swaminathan   switch (candidate)
203*1fd5a2e1SPrashanth Swaminathan     {
204*1fd5a2e1SPrashanth Swaminathan     case FFI_TYPE_FLOAT:
205*1fd5a2e1SPrashanth Swaminathan       ele_count = size / sizeof(float);
206*1fd5a2e1SPrashanth Swaminathan       if (size != ele_count * sizeof(float))
207*1fd5a2e1SPrashanth Swaminathan         return 0;
208*1fd5a2e1SPrashanth Swaminathan       break;
209*1fd5a2e1SPrashanth Swaminathan     case FFI_TYPE_DOUBLE:
210*1fd5a2e1SPrashanth Swaminathan       ele_count = size / sizeof(double);
211*1fd5a2e1SPrashanth Swaminathan       if (size != ele_count * sizeof(double))
212*1fd5a2e1SPrashanth Swaminathan         return 0;
213*1fd5a2e1SPrashanth Swaminathan       break;
214*1fd5a2e1SPrashanth Swaminathan     case FFI_TYPE_LONGDOUBLE:
215*1fd5a2e1SPrashanth Swaminathan       ele_count = size / sizeof(long double);
216*1fd5a2e1SPrashanth Swaminathan       if (size != ele_count * sizeof(long double))
217*1fd5a2e1SPrashanth Swaminathan         return 0;
218*1fd5a2e1SPrashanth Swaminathan       break;
219*1fd5a2e1SPrashanth Swaminathan     default:
220*1fd5a2e1SPrashanth Swaminathan       return 0;
221*1fd5a2e1SPrashanth Swaminathan     }
222*1fd5a2e1SPrashanth Swaminathan   if (ele_count > 4)
223*1fd5a2e1SPrashanth Swaminathan     return 0;
224*1fd5a2e1SPrashanth Swaminathan 
225*1fd5a2e1SPrashanth Swaminathan   /* Finally, make sure that all scalar elements are the same type.  */
226*1fd5a2e1SPrashanth Swaminathan   for (i = 0; elements[i]; ++i)
227*1fd5a2e1SPrashanth Swaminathan     {
228*1fd5a2e1SPrashanth Swaminathan       int t = elements[i]->type;
229*1fd5a2e1SPrashanth Swaminathan       if (t == FFI_TYPE_STRUCT || t == FFI_TYPE_COMPLEX)
230*1fd5a2e1SPrashanth Swaminathan         {
231*1fd5a2e1SPrashanth Swaminathan           if (!is_hfa1 (elements[i], candidate))
232*1fd5a2e1SPrashanth Swaminathan             return 0;
233*1fd5a2e1SPrashanth Swaminathan         }
234*1fd5a2e1SPrashanth Swaminathan       else if (t != candidate)
235*1fd5a2e1SPrashanth Swaminathan         return 0;
236*1fd5a2e1SPrashanth Swaminathan     }
237*1fd5a2e1SPrashanth Swaminathan 
238*1fd5a2e1SPrashanth Swaminathan   /* All tests succeeded.  Encode the result.  */
239*1fd5a2e1SPrashanth Swaminathan  done:
240*1fd5a2e1SPrashanth Swaminathan   return candidate * 4 + (4 - (int)ele_count);
241*1fd5a2e1SPrashanth Swaminathan }
242*1fd5a2e1SPrashanth Swaminathan 
243*1fd5a2e1SPrashanth Swaminathan /* Representation of the procedure call argument marshalling
244*1fd5a2e1SPrashanth Swaminathan    state.
245*1fd5a2e1SPrashanth Swaminathan 
246*1fd5a2e1SPrashanth Swaminathan    The terse state variable names match the names used in the AARCH64
247*1fd5a2e1SPrashanth Swaminathan    PCS. */
248*1fd5a2e1SPrashanth Swaminathan 
249*1fd5a2e1SPrashanth Swaminathan struct arg_state
250*1fd5a2e1SPrashanth Swaminathan {
251*1fd5a2e1SPrashanth Swaminathan   unsigned ngrn;                /* Next general-purpose register number. */
252*1fd5a2e1SPrashanth Swaminathan   unsigned nsrn;                /* Next vector register number. */
253*1fd5a2e1SPrashanth Swaminathan   size_t nsaa;                  /* Next stack offset. */
254*1fd5a2e1SPrashanth Swaminathan 
255*1fd5a2e1SPrashanth Swaminathan #if defined (__APPLE__)
256*1fd5a2e1SPrashanth Swaminathan   unsigned allocating_variadic;
257*1fd5a2e1SPrashanth Swaminathan #endif
258*1fd5a2e1SPrashanth Swaminathan };
259*1fd5a2e1SPrashanth Swaminathan 
260*1fd5a2e1SPrashanth Swaminathan /* Initialize a procedure call argument marshalling state.  */
261*1fd5a2e1SPrashanth Swaminathan static void
arg_init(struct arg_state * state)262*1fd5a2e1SPrashanth Swaminathan arg_init (struct arg_state *state)
263*1fd5a2e1SPrashanth Swaminathan {
264*1fd5a2e1SPrashanth Swaminathan   state->ngrn = 0;
265*1fd5a2e1SPrashanth Swaminathan   state->nsrn = 0;
266*1fd5a2e1SPrashanth Swaminathan   state->nsaa = 0;
267*1fd5a2e1SPrashanth Swaminathan #if defined (__APPLE__)
268*1fd5a2e1SPrashanth Swaminathan   state->allocating_variadic = 0;
269*1fd5a2e1SPrashanth Swaminathan #endif
270*1fd5a2e1SPrashanth Swaminathan }
271*1fd5a2e1SPrashanth Swaminathan 
272*1fd5a2e1SPrashanth Swaminathan /* Allocate an aligned slot on the stack and return a pointer to it.  */
273*1fd5a2e1SPrashanth Swaminathan static void *
allocate_to_stack(struct arg_state * state,void * stack,size_t alignment,size_t size)274*1fd5a2e1SPrashanth Swaminathan allocate_to_stack (struct arg_state *state, void *stack,
275*1fd5a2e1SPrashanth Swaminathan 		   size_t alignment, size_t size)
276*1fd5a2e1SPrashanth Swaminathan {
277*1fd5a2e1SPrashanth Swaminathan   size_t nsaa = state->nsaa;
278*1fd5a2e1SPrashanth Swaminathan 
279*1fd5a2e1SPrashanth Swaminathan   /* Round up the NSAA to the larger of 8 or the natural
280*1fd5a2e1SPrashanth Swaminathan      alignment of the argument's type.  */
281*1fd5a2e1SPrashanth Swaminathan #if defined (__APPLE__)
282*1fd5a2e1SPrashanth Swaminathan   if (state->allocating_variadic && alignment < 8)
283*1fd5a2e1SPrashanth Swaminathan     alignment = 8;
284*1fd5a2e1SPrashanth Swaminathan #else
285*1fd5a2e1SPrashanth Swaminathan   if (alignment < 8)
286*1fd5a2e1SPrashanth Swaminathan     alignment = 8;
287*1fd5a2e1SPrashanth Swaminathan #endif
288*1fd5a2e1SPrashanth Swaminathan 
289*1fd5a2e1SPrashanth Swaminathan   nsaa = FFI_ALIGN (nsaa, alignment);
290*1fd5a2e1SPrashanth Swaminathan   state->nsaa = nsaa + size;
291*1fd5a2e1SPrashanth Swaminathan 
292*1fd5a2e1SPrashanth Swaminathan   return (char *)stack + nsaa;
293*1fd5a2e1SPrashanth Swaminathan }
294*1fd5a2e1SPrashanth Swaminathan 
295*1fd5a2e1SPrashanth Swaminathan static ffi_arg
extend_integer_type(void * source,int type)296*1fd5a2e1SPrashanth Swaminathan extend_integer_type (void *source, int type)
297*1fd5a2e1SPrashanth Swaminathan {
298*1fd5a2e1SPrashanth Swaminathan   switch (type)
299*1fd5a2e1SPrashanth Swaminathan     {
300*1fd5a2e1SPrashanth Swaminathan     case FFI_TYPE_UINT8:
301*1fd5a2e1SPrashanth Swaminathan       return *(UINT8 *) source;
302*1fd5a2e1SPrashanth Swaminathan     case FFI_TYPE_SINT8:
303*1fd5a2e1SPrashanth Swaminathan       return *(SINT8 *) source;
304*1fd5a2e1SPrashanth Swaminathan     case FFI_TYPE_UINT16:
305*1fd5a2e1SPrashanth Swaminathan       return *(UINT16 *) source;
306*1fd5a2e1SPrashanth Swaminathan     case FFI_TYPE_SINT16:
307*1fd5a2e1SPrashanth Swaminathan       return *(SINT16 *) source;
308*1fd5a2e1SPrashanth Swaminathan     case FFI_TYPE_UINT32:
309*1fd5a2e1SPrashanth Swaminathan       return *(UINT32 *) source;
310*1fd5a2e1SPrashanth Swaminathan     case FFI_TYPE_INT:
311*1fd5a2e1SPrashanth Swaminathan     case FFI_TYPE_SINT32:
312*1fd5a2e1SPrashanth Swaminathan       return *(SINT32 *) source;
313*1fd5a2e1SPrashanth Swaminathan     case FFI_TYPE_UINT64:
314*1fd5a2e1SPrashanth Swaminathan     case FFI_TYPE_SINT64:
315*1fd5a2e1SPrashanth Swaminathan       return *(UINT64 *) source;
316*1fd5a2e1SPrashanth Swaminathan       break;
317*1fd5a2e1SPrashanth Swaminathan     case FFI_TYPE_POINTER:
318*1fd5a2e1SPrashanth Swaminathan       return *(uintptr_t *) source;
319*1fd5a2e1SPrashanth Swaminathan     default:
320*1fd5a2e1SPrashanth Swaminathan       abort();
321*1fd5a2e1SPrashanth Swaminathan     }
322*1fd5a2e1SPrashanth Swaminathan }
323*1fd5a2e1SPrashanth Swaminathan 
324*1fd5a2e1SPrashanth Swaminathan #if defined(_MSC_VER)
325*1fd5a2e1SPrashanth Swaminathan void extend_hfa_type (void *dest, void *src, int h);
326*1fd5a2e1SPrashanth Swaminathan #else
327*1fd5a2e1SPrashanth Swaminathan static void
extend_hfa_type(void * dest,void * src,int h)328*1fd5a2e1SPrashanth Swaminathan extend_hfa_type (void *dest, void *src, int h)
329*1fd5a2e1SPrashanth Swaminathan {
330*1fd5a2e1SPrashanth Swaminathan   ssize_t f = h - AARCH64_RET_S4;
331*1fd5a2e1SPrashanth Swaminathan   void *x0;
332*1fd5a2e1SPrashanth Swaminathan 
333*1fd5a2e1SPrashanth Swaminathan   asm volatile (
334*1fd5a2e1SPrashanth Swaminathan 	"adr	%0, 0f\n"
335*1fd5a2e1SPrashanth Swaminathan "	add	%0, %0, %1\n"
336*1fd5a2e1SPrashanth Swaminathan "	br	%0\n"
337*1fd5a2e1SPrashanth Swaminathan "0:	ldp	s16, s17, [%3]\n"	/* S4 */
338*1fd5a2e1SPrashanth Swaminathan "	ldp	s18, s19, [%3, #8]\n"
339*1fd5a2e1SPrashanth Swaminathan "	b	4f\n"
340*1fd5a2e1SPrashanth Swaminathan "	ldp	s16, s17, [%3]\n"	/* S3 */
341*1fd5a2e1SPrashanth Swaminathan "	ldr	s18, [%3, #8]\n"
342*1fd5a2e1SPrashanth Swaminathan "	b	3f\n"
343*1fd5a2e1SPrashanth Swaminathan "	ldp	s16, s17, [%3]\n"	/* S2 */
344*1fd5a2e1SPrashanth Swaminathan "	b	2f\n"
345*1fd5a2e1SPrashanth Swaminathan "	nop\n"
346*1fd5a2e1SPrashanth Swaminathan "	ldr	s16, [%3]\n"		/* S1 */
347*1fd5a2e1SPrashanth Swaminathan "	b	1f\n"
348*1fd5a2e1SPrashanth Swaminathan "	nop\n"
349*1fd5a2e1SPrashanth Swaminathan "	ldp	d16, d17, [%3]\n"	/* D4 */
350*1fd5a2e1SPrashanth Swaminathan "	ldp	d18, d19, [%3, #16]\n"
351*1fd5a2e1SPrashanth Swaminathan "	b	4f\n"
352*1fd5a2e1SPrashanth Swaminathan "	ldp	d16, d17, [%3]\n"	/* D3 */
353*1fd5a2e1SPrashanth Swaminathan "	ldr	d18, [%3, #16]\n"
354*1fd5a2e1SPrashanth Swaminathan "	b	3f\n"
355*1fd5a2e1SPrashanth Swaminathan "	ldp	d16, d17, [%3]\n"	/* D2 */
356*1fd5a2e1SPrashanth Swaminathan "	b	2f\n"
357*1fd5a2e1SPrashanth Swaminathan "	nop\n"
358*1fd5a2e1SPrashanth Swaminathan "	ldr	d16, [%3]\n"		/* D1 */
359*1fd5a2e1SPrashanth Swaminathan "	b	1f\n"
360*1fd5a2e1SPrashanth Swaminathan "	nop\n"
361*1fd5a2e1SPrashanth Swaminathan "	ldp	q16, q17, [%3]\n"	/* Q4 */
362*1fd5a2e1SPrashanth Swaminathan "	ldp	q18, q19, [%3, #32]\n"
363*1fd5a2e1SPrashanth Swaminathan "	b	4f\n"
364*1fd5a2e1SPrashanth Swaminathan "	ldp	q16, q17, [%3]\n"	/* Q3 */
365*1fd5a2e1SPrashanth Swaminathan "	ldr	q18, [%3, #32]\n"
366*1fd5a2e1SPrashanth Swaminathan "	b	3f\n"
367*1fd5a2e1SPrashanth Swaminathan "	ldp	q16, q17, [%3]\n"	/* Q2 */
368*1fd5a2e1SPrashanth Swaminathan "	b	2f\n"
369*1fd5a2e1SPrashanth Swaminathan "	nop\n"
370*1fd5a2e1SPrashanth Swaminathan "	ldr	q16, [%3]\n"		/* Q1 */
371*1fd5a2e1SPrashanth Swaminathan "	b	1f\n"
372*1fd5a2e1SPrashanth Swaminathan "4:	str	q19, [%2, #48]\n"
373*1fd5a2e1SPrashanth Swaminathan "3:	str	q18, [%2, #32]\n"
374*1fd5a2e1SPrashanth Swaminathan "2:	str	q17, [%2, #16]\n"
375*1fd5a2e1SPrashanth Swaminathan "1:	str	q16, [%2]"
376*1fd5a2e1SPrashanth Swaminathan     : "=&r"(x0)
377*1fd5a2e1SPrashanth Swaminathan     : "r"(f * 12), "r"(dest), "r"(src)
378*1fd5a2e1SPrashanth Swaminathan     : "memory", "v16", "v17", "v18", "v19");
379*1fd5a2e1SPrashanth Swaminathan }
380*1fd5a2e1SPrashanth Swaminathan #endif
381*1fd5a2e1SPrashanth Swaminathan 
382*1fd5a2e1SPrashanth Swaminathan #if defined(_MSC_VER)
383*1fd5a2e1SPrashanth Swaminathan void* compress_hfa_type (void *dest, void *src, int h);
384*1fd5a2e1SPrashanth Swaminathan #else
385*1fd5a2e1SPrashanth Swaminathan static void *
compress_hfa_type(void * dest,void * reg,int h)386*1fd5a2e1SPrashanth Swaminathan compress_hfa_type (void *dest, void *reg, int h)
387*1fd5a2e1SPrashanth Swaminathan {
388*1fd5a2e1SPrashanth Swaminathan   switch (h)
389*1fd5a2e1SPrashanth Swaminathan     {
390*1fd5a2e1SPrashanth Swaminathan     case AARCH64_RET_S1:
391*1fd5a2e1SPrashanth Swaminathan       if (dest == reg)
392*1fd5a2e1SPrashanth Swaminathan 	{
393*1fd5a2e1SPrashanth Swaminathan #ifdef __AARCH64EB__
394*1fd5a2e1SPrashanth Swaminathan 	  dest += 12;
395*1fd5a2e1SPrashanth Swaminathan #endif
396*1fd5a2e1SPrashanth Swaminathan 	}
397*1fd5a2e1SPrashanth Swaminathan       else
398*1fd5a2e1SPrashanth Swaminathan 	*(float *)dest = *(float *)reg;
399*1fd5a2e1SPrashanth Swaminathan       break;
400*1fd5a2e1SPrashanth Swaminathan     case AARCH64_RET_S2:
401*1fd5a2e1SPrashanth Swaminathan       asm ("ldp q16, q17, [%1]\n\t"
402*1fd5a2e1SPrashanth Swaminathan 	   "st2 { v16.s, v17.s }[0], [%0]"
403*1fd5a2e1SPrashanth Swaminathan 	   : : "r"(dest), "r"(reg) : "memory", "v16", "v17");
404*1fd5a2e1SPrashanth Swaminathan       break;
405*1fd5a2e1SPrashanth Swaminathan     case AARCH64_RET_S3:
406*1fd5a2e1SPrashanth Swaminathan       asm ("ldp q16, q17, [%1]\n\t"
407*1fd5a2e1SPrashanth Swaminathan 	   "ldr q18, [%1, #32]\n\t"
408*1fd5a2e1SPrashanth Swaminathan 	   "st3 { v16.s, v17.s, v18.s }[0], [%0]"
409*1fd5a2e1SPrashanth Swaminathan 	   : : "r"(dest), "r"(reg) : "memory", "v16", "v17", "v18");
410*1fd5a2e1SPrashanth Swaminathan       break;
411*1fd5a2e1SPrashanth Swaminathan     case AARCH64_RET_S4:
412*1fd5a2e1SPrashanth Swaminathan       asm ("ldp q16, q17, [%1]\n\t"
413*1fd5a2e1SPrashanth Swaminathan 	   "ldp q18, q19, [%1, #32]\n\t"
414*1fd5a2e1SPrashanth Swaminathan 	   "st4 { v16.s, v17.s, v18.s, v19.s }[0], [%0]"
415*1fd5a2e1SPrashanth Swaminathan 	   : : "r"(dest), "r"(reg) : "memory", "v16", "v17", "v18", "v19");
416*1fd5a2e1SPrashanth Swaminathan       break;
417*1fd5a2e1SPrashanth Swaminathan 
418*1fd5a2e1SPrashanth Swaminathan     case AARCH64_RET_D1:
419*1fd5a2e1SPrashanth Swaminathan       if (dest == reg)
420*1fd5a2e1SPrashanth Swaminathan 	{
421*1fd5a2e1SPrashanth Swaminathan #ifdef __AARCH64EB__
422*1fd5a2e1SPrashanth Swaminathan 	  dest += 8;
423*1fd5a2e1SPrashanth Swaminathan #endif
424*1fd5a2e1SPrashanth Swaminathan 	}
425*1fd5a2e1SPrashanth Swaminathan       else
426*1fd5a2e1SPrashanth Swaminathan 	*(double *)dest = *(double *)reg;
427*1fd5a2e1SPrashanth Swaminathan       break;
428*1fd5a2e1SPrashanth Swaminathan     case AARCH64_RET_D2:
429*1fd5a2e1SPrashanth Swaminathan       asm ("ldp q16, q17, [%1]\n\t"
430*1fd5a2e1SPrashanth Swaminathan 	   "st2 { v16.d, v17.d }[0], [%0]"
431*1fd5a2e1SPrashanth Swaminathan 	   : : "r"(dest), "r"(reg) : "memory", "v16", "v17");
432*1fd5a2e1SPrashanth Swaminathan       break;
433*1fd5a2e1SPrashanth Swaminathan     case AARCH64_RET_D3:
434*1fd5a2e1SPrashanth Swaminathan       asm ("ldp q16, q17, [%1]\n\t"
435*1fd5a2e1SPrashanth Swaminathan 	   "ldr q18, [%1, #32]\n\t"
436*1fd5a2e1SPrashanth Swaminathan 	   "st3 { v16.d, v17.d, v18.d }[0], [%0]"
437*1fd5a2e1SPrashanth Swaminathan 	   : : "r"(dest), "r"(reg) : "memory", "v16", "v17", "v18");
438*1fd5a2e1SPrashanth Swaminathan       break;
439*1fd5a2e1SPrashanth Swaminathan     case AARCH64_RET_D4:
440*1fd5a2e1SPrashanth Swaminathan       asm ("ldp q16, q17, [%1]\n\t"
441*1fd5a2e1SPrashanth Swaminathan 	   "ldp q18, q19, [%1, #32]\n\t"
442*1fd5a2e1SPrashanth Swaminathan 	   "st4 { v16.d, v17.d, v18.d, v19.d }[0], [%0]"
443*1fd5a2e1SPrashanth Swaminathan 	   : : "r"(dest), "r"(reg) : "memory", "v16", "v17", "v18", "v19");
444*1fd5a2e1SPrashanth Swaminathan       break;
445*1fd5a2e1SPrashanth Swaminathan 
446*1fd5a2e1SPrashanth Swaminathan     default:
447*1fd5a2e1SPrashanth Swaminathan       if (dest != reg)
448*1fd5a2e1SPrashanth Swaminathan 	return memcpy (dest, reg, 16 * (4 - (h & 3)));
449*1fd5a2e1SPrashanth Swaminathan       break;
450*1fd5a2e1SPrashanth Swaminathan     }
451*1fd5a2e1SPrashanth Swaminathan   return dest;
452*1fd5a2e1SPrashanth Swaminathan }
453*1fd5a2e1SPrashanth Swaminathan #endif
454*1fd5a2e1SPrashanth Swaminathan 
455*1fd5a2e1SPrashanth Swaminathan /* Either allocate an appropriate register for the argument type, or if
456*1fd5a2e1SPrashanth Swaminathan    none are available, allocate a stack slot and return a pointer
457*1fd5a2e1SPrashanth Swaminathan    to the allocated space.  */
458*1fd5a2e1SPrashanth Swaminathan 
459*1fd5a2e1SPrashanth Swaminathan static void *
allocate_int_to_reg_or_stack(struct call_context * context,struct arg_state * state,void * stack,size_t size)460*1fd5a2e1SPrashanth Swaminathan allocate_int_to_reg_or_stack (struct call_context *context,
461*1fd5a2e1SPrashanth Swaminathan 			      struct arg_state *state,
462*1fd5a2e1SPrashanth Swaminathan 			      void *stack, size_t size)
463*1fd5a2e1SPrashanth Swaminathan {
464*1fd5a2e1SPrashanth Swaminathan   if (state->ngrn < N_X_ARG_REG)
465*1fd5a2e1SPrashanth Swaminathan     return &context->x[state->ngrn++];
466*1fd5a2e1SPrashanth Swaminathan 
467*1fd5a2e1SPrashanth Swaminathan   state->ngrn = N_X_ARG_REG;
468*1fd5a2e1SPrashanth Swaminathan   return allocate_to_stack (state, stack, size, size);
469*1fd5a2e1SPrashanth Swaminathan }
470*1fd5a2e1SPrashanth Swaminathan 
471*1fd5a2e1SPrashanth Swaminathan ffi_status FFI_HIDDEN
ffi_prep_cif_machdep(ffi_cif * cif)472*1fd5a2e1SPrashanth Swaminathan ffi_prep_cif_machdep (ffi_cif *cif)
473*1fd5a2e1SPrashanth Swaminathan {
474*1fd5a2e1SPrashanth Swaminathan   ffi_type *rtype = cif->rtype;
475*1fd5a2e1SPrashanth Swaminathan   size_t bytes = cif->bytes;
476*1fd5a2e1SPrashanth Swaminathan   int flags, i, n;
477*1fd5a2e1SPrashanth Swaminathan 
478*1fd5a2e1SPrashanth Swaminathan   switch (rtype->type)
479*1fd5a2e1SPrashanth Swaminathan     {
480*1fd5a2e1SPrashanth Swaminathan     case FFI_TYPE_VOID:
481*1fd5a2e1SPrashanth Swaminathan       flags = AARCH64_RET_VOID;
482*1fd5a2e1SPrashanth Swaminathan       break;
483*1fd5a2e1SPrashanth Swaminathan     case FFI_TYPE_UINT8:
484*1fd5a2e1SPrashanth Swaminathan       flags = AARCH64_RET_UINT8;
485*1fd5a2e1SPrashanth Swaminathan       break;
486*1fd5a2e1SPrashanth Swaminathan     case FFI_TYPE_UINT16:
487*1fd5a2e1SPrashanth Swaminathan       flags = AARCH64_RET_UINT16;
488*1fd5a2e1SPrashanth Swaminathan       break;
489*1fd5a2e1SPrashanth Swaminathan     case FFI_TYPE_UINT32:
490*1fd5a2e1SPrashanth Swaminathan       flags = AARCH64_RET_UINT32;
491*1fd5a2e1SPrashanth Swaminathan       break;
492*1fd5a2e1SPrashanth Swaminathan     case FFI_TYPE_SINT8:
493*1fd5a2e1SPrashanth Swaminathan       flags = AARCH64_RET_SINT8;
494*1fd5a2e1SPrashanth Swaminathan       break;
495*1fd5a2e1SPrashanth Swaminathan     case FFI_TYPE_SINT16:
496*1fd5a2e1SPrashanth Swaminathan       flags = AARCH64_RET_SINT16;
497*1fd5a2e1SPrashanth Swaminathan       break;
498*1fd5a2e1SPrashanth Swaminathan     case FFI_TYPE_INT:
499*1fd5a2e1SPrashanth Swaminathan     case FFI_TYPE_SINT32:
500*1fd5a2e1SPrashanth Swaminathan       flags = AARCH64_RET_SINT32;
501*1fd5a2e1SPrashanth Swaminathan       break;
502*1fd5a2e1SPrashanth Swaminathan     case FFI_TYPE_SINT64:
503*1fd5a2e1SPrashanth Swaminathan     case FFI_TYPE_UINT64:
504*1fd5a2e1SPrashanth Swaminathan       flags = AARCH64_RET_INT64;
505*1fd5a2e1SPrashanth Swaminathan       break;
506*1fd5a2e1SPrashanth Swaminathan     case FFI_TYPE_POINTER:
507*1fd5a2e1SPrashanth Swaminathan       flags = (sizeof(void *) == 4 ? AARCH64_RET_UINT32 : AARCH64_RET_INT64);
508*1fd5a2e1SPrashanth Swaminathan       break;
509*1fd5a2e1SPrashanth Swaminathan 
510*1fd5a2e1SPrashanth Swaminathan     case FFI_TYPE_FLOAT:
511*1fd5a2e1SPrashanth Swaminathan     case FFI_TYPE_DOUBLE:
512*1fd5a2e1SPrashanth Swaminathan     case FFI_TYPE_LONGDOUBLE:
513*1fd5a2e1SPrashanth Swaminathan     case FFI_TYPE_STRUCT:
514*1fd5a2e1SPrashanth Swaminathan     case FFI_TYPE_COMPLEX:
515*1fd5a2e1SPrashanth Swaminathan       flags = is_vfp_type (rtype);
516*1fd5a2e1SPrashanth Swaminathan       if (flags == 0)
517*1fd5a2e1SPrashanth Swaminathan 	{
518*1fd5a2e1SPrashanth Swaminathan 	  size_t s = rtype->size;
519*1fd5a2e1SPrashanth Swaminathan 	  if (s > 16)
520*1fd5a2e1SPrashanth Swaminathan 	    {
521*1fd5a2e1SPrashanth Swaminathan 	      flags = AARCH64_RET_VOID | AARCH64_RET_IN_MEM;
522*1fd5a2e1SPrashanth Swaminathan 	      bytes += 8;
523*1fd5a2e1SPrashanth Swaminathan 	    }
524*1fd5a2e1SPrashanth Swaminathan 	  else if (s == 16)
525*1fd5a2e1SPrashanth Swaminathan 	    flags = AARCH64_RET_INT128;
526*1fd5a2e1SPrashanth Swaminathan 	  else if (s == 8)
527*1fd5a2e1SPrashanth Swaminathan 	    flags = AARCH64_RET_INT64;
528*1fd5a2e1SPrashanth Swaminathan 	  else
529*1fd5a2e1SPrashanth Swaminathan 	    flags = AARCH64_RET_INT128 | AARCH64_RET_NEED_COPY;
530*1fd5a2e1SPrashanth Swaminathan 	}
531*1fd5a2e1SPrashanth Swaminathan       break;
532*1fd5a2e1SPrashanth Swaminathan 
533*1fd5a2e1SPrashanth Swaminathan     default:
534*1fd5a2e1SPrashanth Swaminathan       abort();
535*1fd5a2e1SPrashanth Swaminathan     }
536*1fd5a2e1SPrashanth Swaminathan 
537*1fd5a2e1SPrashanth Swaminathan   for (i = 0, n = cif->nargs; i < n; i++)
538*1fd5a2e1SPrashanth Swaminathan     if (is_vfp_type (cif->arg_types[i]))
539*1fd5a2e1SPrashanth Swaminathan       {
540*1fd5a2e1SPrashanth Swaminathan 	flags |= AARCH64_FLAG_ARG_V;
541*1fd5a2e1SPrashanth Swaminathan 	break;
542*1fd5a2e1SPrashanth Swaminathan       }
543*1fd5a2e1SPrashanth Swaminathan 
544*1fd5a2e1SPrashanth Swaminathan   /* Round the stack up to a multiple of the stack alignment requirement. */
545*1fd5a2e1SPrashanth Swaminathan   cif->bytes = (unsigned) FFI_ALIGN(bytes, 16);
546*1fd5a2e1SPrashanth Swaminathan   cif->flags = flags;
547*1fd5a2e1SPrashanth Swaminathan #if defined (__APPLE__)
548*1fd5a2e1SPrashanth Swaminathan   cif->aarch64_nfixedargs = 0;
549*1fd5a2e1SPrashanth Swaminathan #endif
550*1fd5a2e1SPrashanth Swaminathan 
551*1fd5a2e1SPrashanth Swaminathan   return FFI_OK;
552*1fd5a2e1SPrashanth Swaminathan }
553*1fd5a2e1SPrashanth Swaminathan 
554*1fd5a2e1SPrashanth Swaminathan #if defined (__APPLE__)
555*1fd5a2e1SPrashanth Swaminathan /* Perform Apple-specific cif processing for variadic calls */
556*1fd5a2e1SPrashanth Swaminathan ffi_status FFI_HIDDEN
ffi_prep_cif_machdep_var(ffi_cif * cif,unsigned int nfixedargs,unsigned int ntotalargs)557*1fd5a2e1SPrashanth Swaminathan ffi_prep_cif_machdep_var(ffi_cif *cif, unsigned int nfixedargs,
558*1fd5a2e1SPrashanth Swaminathan 			 unsigned int ntotalargs)
559*1fd5a2e1SPrashanth Swaminathan {
560*1fd5a2e1SPrashanth Swaminathan   ffi_status status = ffi_prep_cif_machdep (cif);
561*1fd5a2e1SPrashanth Swaminathan   cif->aarch64_nfixedargs = nfixedargs;
562*1fd5a2e1SPrashanth Swaminathan   return status;
563*1fd5a2e1SPrashanth Swaminathan }
564*1fd5a2e1SPrashanth Swaminathan #endif /* __APPLE__ */
565*1fd5a2e1SPrashanth Swaminathan 
566*1fd5a2e1SPrashanth Swaminathan extern void ffi_call_SYSV (struct call_context *context, void *frame,
567*1fd5a2e1SPrashanth Swaminathan 			   void (*fn)(void), void *rvalue, int flags,
568*1fd5a2e1SPrashanth Swaminathan 			   void *closure) FFI_HIDDEN;
569*1fd5a2e1SPrashanth Swaminathan 
570*1fd5a2e1SPrashanth Swaminathan /* Call a function with the provided arguments and capture the return
571*1fd5a2e1SPrashanth Swaminathan    value.  */
572*1fd5a2e1SPrashanth Swaminathan static void
ffi_call_int(ffi_cif * cif,void (* fn)(void),void * orig_rvalue,void ** avalue,void * closure)573*1fd5a2e1SPrashanth Swaminathan ffi_call_int (ffi_cif *cif, void (*fn)(void), void *orig_rvalue,
574*1fd5a2e1SPrashanth Swaminathan 	      void **avalue, void *closure)
575*1fd5a2e1SPrashanth Swaminathan {
576*1fd5a2e1SPrashanth Swaminathan   struct call_context *context;
577*1fd5a2e1SPrashanth Swaminathan   void *stack, *frame, *rvalue;
578*1fd5a2e1SPrashanth Swaminathan   struct arg_state state;
579*1fd5a2e1SPrashanth Swaminathan   size_t stack_bytes, rtype_size, rsize;
580*1fd5a2e1SPrashanth Swaminathan   int i, nargs, flags;
581*1fd5a2e1SPrashanth Swaminathan   ffi_type *rtype;
582*1fd5a2e1SPrashanth Swaminathan 
583*1fd5a2e1SPrashanth Swaminathan   flags = cif->flags;
584*1fd5a2e1SPrashanth Swaminathan   rtype = cif->rtype;
585*1fd5a2e1SPrashanth Swaminathan   rtype_size = rtype->size;
586*1fd5a2e1SPrashanth Swaminathan   stack_bytes = cif->bytes;
587*1fd5a2e1SPrashanth Swaminathan 
588*1fd5a2e1SPrashanth Swaminathan   /* If the target function returns a structure via hidden pointer,
589*1fd5a2e1SPrashanth Swaminathan      then we cannot allow a null rvalue.  Otherwise, mash a null
590*1fd5a2e1SPrashanth Swaminathan      rvalue to void return type.  */
591*1fd5a2e1SPrashanth Swaminathan   rsize = 0;
592*1fd5a2e1SPrashanth Swaminathan   if (flags & AARCH64_RET_IN_MEM)
593*1fd5a2e1SPrashanth Swaminathan     {
594*1fd5a2e1SPrashanth Swaminathan       if (orig_rvalue == NULL)
595*1fd5a2e1SPrashanth Swaminathan 	rsize = rtype_size;
596*1fd5a2e1SPrashanth Swaminathan     }
597*1fd5a2e1SPrashanth Swaminathan   else if (orig_rvalue == NULL)
598*1fd5a2e1SPrashanth Swaminathan     flags &= AARCH64_FLAG_ARG_V;
599*1fd5a2e1SPrashanth Swaminathan   else if (flags & AARCH64_RET_NEED_COPY)
600*1fd5a2e1SPrashanth Swaminathan     rsize = 16;
601*1fd5a2e1SPrashanth Swaminathan 
602*1fd5a2e1SPrashanth Swaminathan   /* Allocate consectutive stack for everything we'll need.  */
603*1fd5a2e1SPrashanth Swaminathan   context = alloca (sizeof(struct call_context) + stack_bytes + 32 + rsize);
604*1fd5a2e1SPrashanth Swaminathan   stack = context + 1;
605*1fd5a2e1SPrashanth Swaminathan   frame = (void*)((uintptr_t)stack + (uintptr_t)stack_bytes);
606*1fd5a2e1SPrashanth Swaminathan   rvalue = (rsize ? (void*)((uintptr_t)frame + 32) : orig_rvalue);
607*1fd5a2e1SPrashanth Swaminathan 
608*1fd5a2e1SPrashanth Swaminathan   arg_init (&state);
609*1fd5a2e1SPrashanth Swaminathan   for (i = 0, nargs = cif->nargs; i < nargs; i++)
610*1fd5a2e1SPrashanth Swaminathan     {
611*1fd5a2e1SPrashanth Swaminathan       ffi_type *ty = cif->arg_types[i];
612*1fd5a2e1SPrashanth Swaminathan       size_t s = ty->size;
613*1fd5a2e1SPrashanth Swaminathan       void *a = avalue[i];
614*1fd5a2e1SPrashanth Swaminathan       int h, t;
615*1fd5a2e1SPrashanth Swaminathan 
616*1fd5a2e1SPrashanth Swaminathan       t = ty->type;
617*1fd5a2e1SPrashanth Swaminathan       switch (t)
618*1fd5a2e1SPrashanth Swaminathan 	{
619*1fd5a2e1SPrashanth Swaminathan 	case FFI_TYPE_VOID:
620*1fd5a2e1SPrashanth Swaminathan 	  FFI_ASSERT (0);
621*1fd5a2e1SPrashanth Swaminathan 	  break;
622*1fd5a2e1SPrashanth Swaminathan 
623*1fd5a2e1SPrashanth Swaminathan 	/* If the argument is a basic type the argument is allocated to an
624*1fd5a2e1SPrashanth Swaminathan 	   appropriate register, or if none are available, to the stack.  */
625*1fd5a2e1SPrashanth Swaminathan 	case FFI_TYPE_INT:
626*1fd5a2e1SPrashanth Swaminathan 	case FFI_TYPE_UINT8:
627*1fd5a2e1SPrashanth Swaminathan 	case FFI_TYPE_SINT8:
628*1fd5a2e1SPrashanth Swaminathan 	case FFI_TYPE_UINT16:
629*1fd5a2e1SPrashanth Swaminathan 	case FFI_TYPE_SINT16:
630*1fd5a2e1SPrashanth Swaminathan 	case FFI_TYPE_UINT32:
631*1fd5a2e1SPrashanth Swaminathan 	case FFI_TYPE_SINT32:
632*1fd5a2e1SPrashanth Swaminathan 	case FFI_TYPE_UINT64:
633*1fd5a2e1SPrashanth Swaminathan 	case FFI_TYPE_SINT64:
634*1fd5a2e1SPrashanth Swaminathan 	case FFI_TYPE_POINTER:
635*1fd5a2e1SPrashanth Swaminathan 	do_pointer:
636*1fd5a2e1SPrashanth Swaminathan 	  {
637*1fd5a2e1SPrashanth Swaminathan 	    ffi_arg ext = extend_integer_type (a, t);
638*1fd5a2e1SPrashanth Swaminathan 	    if (state.ngrn < N_X_ARG_REG)
639*1fd5a2e1SPrashanth Swaminathan 	      context->x[state.ngrn++] = ext;
640*1fd5a2e1SPrashanth Swaminathan 	    else
641*1fd5a2e1SPrashanth Swaminathan 	      {
642*1fd5a2e1SPrashanth Swaminathan 		void *d = allocate_to_stack (&state, stack, ty->alignment, s);
643*1fd5a2e1SPrashanth Swaminathan 		state.ngrn = N_X_ARG_REG;
644*1fd5a2e1SPrashanth Swaminathan 		/* Note that the default abi extends each argument
645*1fd5a2e1SPrashanth Swaminathan 		   to a full 64-bit slot, while the iOS abi allocates
646*1fd5a2e1SPrashanth Swaminathan 		   only enough space. */
647*1fd5a2e1SPrashanth Swaminathan #ifdef __APPLE__
648*1fd5a2e1SPrashanth Swaminathan 		memcpy(d, a, s);
649*1fd5a2e1SPrashanth Swaminathan #else
650*1fd5a2e1SPrashanth Swaminathan 		*(ffi_arg *)d = ext;
651*1fd5a2e1SPrashanth Swaminathan #endif
652*1fd5a2e1SPrashanth Swaminathan 	      }
653*1fd5a2e1SPrashanth Swaminathan 	  }
654*1fd5a2e1SPrashanth Swaminathan 	  break;
655*1fd5a2e1SPrashanth Swaminathan 
656*1fd5a2e1SPrashanth Swaminathan 	case FFI_TYPE_FLOAT:
657*1fd5a2e1SPrashanth Swaminathan 	case FFI_TYPE_DOUBLE:
658*1fd5a2e1SPrashanth Swaminathan 	case FFI_TYPE_LONGDOUBLE:
659*1fd5a2e1SPrashanth Swaminathan 	case FFI_TYPE_STRUCT:
660*1fd5a2e1SPrashanth Swaminathan 	case FFI_TYPE_COMPLEX:
661*1fd5a2e1SPrashanth Swaminathan 	  {
662*1fd5a2e1SPrashanth Swaminathan 	    void *dest;
663*1fd5a2e1SPrashanth Swaminathan 
664*1fd5a2e1SPrashanth Swaminathan 	    h = is_vfp_type (ty);
665*1fd5a2e1SPrashanth Swaminathan 	    if (h)
666*1fd5a2e1SPrashanth Swaminathan 	      {
667*1fd5a2e1SPrashanth Swaminathan 		int elems = 4 - (h & 3);
668*1fd5a2e1SPrashanth Swaminathan #ifdef _M_ARM64 /* for handling armasm calling convention */
669*1fd5a2e1SPrashanth Swaminathan                 if (cif->is_variadic)
670*1fd5a2e1SPrashanth Swaminathan                   {
671*1fd5a2e1SPrashanth Swaminathan                     if (state.ngrn + elems <= N_X_ARG_REG)
672*1fd5a2e1SPrashanth Swaminathan                       {
673*1fd5a2e1SPrashanth Swaminathan                         dest = &context->x[state.ngrn];
674*1fd5a2e1SPrashanth Swaminathan                         state.ngrn += elems;
675*1fd5a2e1SPrashanth Swaminathan                         extend_hfa_type(dest, a, h);
676*1fd5a2e1SPrashanth Swaminathan                         break;
677*1fd5a2e1SPrashanth Swaminathan                       }
678*1fd5a2e1SPrashanth Swaminathan                     state.nsrn = N_X_ARG_REG;
679*1fd5a2e1SPrashanth Swaminathan                     dest = allocate_to_stack(&state, stack, ty->alignment, s);
680*1fd5a2e1SPrashanth Swaminathan                   }
681*1fd5a2e1SPrashanth Swaminathan                 else
682*1fd5a2e1SPrashanth Swaminathan                   {
683*1fd5a2e1SPrashanth Swaminathan #endif /* for handling armasm calling convention */
684*1fd5a2e1SPrashanth Swaminathan 	        if (state.nsrn + elems <= N_V_ARG_REG)
685*1fd5a2e1SPrashanth Swaminathan 		  {
686*1fd5a2e1SPrashanth Swaminathan 		    dest = &context->v[state.nsrn];
687*1fd5a2e1SPrashanth Swaminathan 		    state.nsrn += elems;
688*1fd5a2e1SPrashanth Swaminathan 		    extend_hfa_type (dest, a, h);
689*1fd5a2e1SPrashanth Swaminathan 		    break;
690*1fd5a2e1SPrashanth Swaminathan 		  }
691*1fd5a2e1SPrashanth Swaminathan 		state.nsrn = N_V_ARG_REG;
692*1fd5a2e1SPrashanth Swaminathan 		dest = allocate_to_stack (&state, stack, ty->alignment, s);
693*1fd5a2e1SPrashanth Swaminathan #ifdef _M_ARM64 /* for handling armasm calling convention */
694*1fd5a2e1SPrashanth Swaminathan 	      }
695*1fd5a2e1SPrashanth Swaminathan #endif /* for handling armasm calling convention */
696*1fd5a2e1SPrashanth Swaminathan 	      }
697*1fd5a2e1SPrashanth Swaminathan 	    else if (s > 16)
698*1fd5a2e1SPrashanth Swaminathan 	      {
699*1fd5a2e1SPrashanth Swaminathan 		/* If the argument is a composite type that is larger than 16
700*1fd5a2e1SPrashanth Swaminathan 		   bytes, then the argument has been copied to memory, and
701*1fd5a2e1SPrashanth Swaminathan 		   the argument is replaced by a pointer to the copy.  */
702*1fd5a2e1SPrashanth Swaminathan 		a = &avalue[i];
703*1fd5a2e1SPrashanth Swaminathan 		t = FFI_TYPE_POINTER;
704*1fd5a2e1SPrashanth Swaminathan 		s = sizeof (void *);
705*1fd5a2e1SPrashanth Swaminathan 		goto do_pointer;
706*1fd5a2e1SPrashanth Swaminathan 	      }
707*1fd5a2e1SPrashanth Swaminathan 	    else
708*1fd5a2e1SPrashanth Swaminathan 	      {
709*1fd5a2e1SPrashanth Swaminathan 		size_t n = (s + 7) / 8;
710*1fd5a2e1SPrashanth Swaminathan 		if (state.ngrn + n <= N_X_ARG_REG)
711*1fd5a2e1SPrashanth Swaminathan 		  {
712*1fd5a2e1SPrashanth Swaminathan 		    /* If the argument is a composite type and the size in
713*1fd5a2e1SPrashanth Swaminathan 		       double-words is not more than the number of available
714*1fd5a2e1SPrashanth Swaminathan 		       X registers, then the argument is copied into
715*1fd5a2e1SPrashanth Swaminathan 		       consecutive X registers.  */
716*1fd5a2e1SPrashanth Swaminathan 		    dest = &context->x[state.ngrn];
717*1fd5a2e1SPrashanth Swaminathan                     state.ngrn += (unsigned int)n;
718*1fd5a2e1SPrashanth Swaminathan 		  }
719*1fd5a2e1SPrashanth Swaminathan 		else
720*1fd5a2e1SPrashanth Swaminathan 		  {
721*1fd5a2e1SPrashanth Swaminathan 		    /* Otherwise, there are insufficient X registers. Further
722*1fd5a2e1SPrashanth Swaminathan 		       X register allocations are prevented, the NSAA is
723*1fd5a2e1SPrashanth Swaminathan 		       adjusted and the argument is copied to memory at the
724*1fd5a2e1SPrashanth Swaminathan 		       adjusted NSAA.  */
725*1fd5a2e1SPrashanth Swaminathan 		    state.ngrn = N_X_ARG_REG;
726*1fd5a2e1SPrashanth Swaminathan 		    dest = allocate_to_stack (&state, stack, ty->alignment, s);
727*1fd5a2e1SPrashanth Swaminathan 		  }
728*1fd5a2e1SPrashanth Swaminathan 		}
729*1fd5a2e1SPrashanth Swaminathan 	      memcpy (dest, a, s);
730*1fd5a2e1SPrashanth Swaminathan 	    }
731*1fd5a2e1SPrashanth Swaminathan 	  break;
732*1fd5a2e1SPrashanth Swaminathan 
733*1fd5a2e1SPrashanth Swaminathan 	default:
734*1fd5a2e1SPrashanth Swaminathan 	  abort();
735*1fd5a2e1SPrashanth Swaminathan 	}
736*1fd5a2e1SPrashanth Swaminathan 
737*1fd5a2e1SPrashanth Swaminathan #if defined (__APPLE__)
738*1fd5a2e1SPrashanth Swaminathan       if (i + 1 == cif->aarch64_nfixedargs)
739*1fd5a2e1SPrashanth Swaminathan 	{
740*1fd5a2e1SPrashanth Swaminathan 	  state.ngrn = N_X_ARG_REG;
741*1fd5a2e1SPrashanth Swaminathan 	  state.nsrn = N_V_ARG_REG;
742*1fd5a2e1SPrashanth Swaminathan 	  state.allocating_variadic = 1;
743*1fd5a2e1SPrashanth Swaminathan 	}
744*1fd5a2e1SPrashanth Swaminathan #endif
745*1fd5a2e1SPrashanth Swaminathan     }
746*1fd5a2e1SPrashanth Swaminathan 
747*1fd5a2e1SPrashanth Swaminathan   ffi_call_SYSV (context, frame, fn, rvalue, flags, closure);
748*1fd5a2e1SPrashanth Swaminathan 
749*1fd5a2e1SPrashanth Swaminathan   if (flags & AARCH64_RET_NEED_COPY)
750*1fd5a2e1SPrashanth Swaminathan     memcpy (orig_rvalue, rvalue, rtype_size);
751*1fd5a2e1SPrashanth Swaminathan }
752*1fd5a2e1SPrashanth Swaminathan 
753*1fd5a2e1SPrashanth Swaminathan void
ffi_call(ffi_cif * cif,void (* fn)(void),void * rvalue,void ** avalue)754*1fd5a2e1SPrashanth Swaminathan ffi_call (ffi_cif *cif, void (*fn) (void), void *rvalue, void **avalue)
755*1fd5a2e1SPrashanth Swaminathan {
756*1fd5a2e1SPrashanth Swaminathan   ffi_call_int (cif, fn, rvalue, avalue, NULL);
757*1fd5a2e1SPrashanth Swaminathan }
758*1fd5a2e1SPrashanth Swaminathan 
759*1fd5a2e1SPrashanth Swaminathan #ifdef FFI_GO_CLOSURES
760*1fd5a2e1SPrashanth Swaminathan void
ffi_call_go(ffi_cif * cif,void (* fn)(void),void * rvalue,void ** avalue,void * closure)761*1fd5a2e1SPrashanth Swaminathan ffi_call_go (ffi_cif *cif, void (*fn) (void), void *rvalue,
762*1fd5a2e1SPrashanth Swaminathan 	     void **avalue, void *closure)
763*1fd5a2e1SPrashanth Swaminathan {
764*1fd5a2e1SPrashanth Swaminathan   ffi_call_int (cif, fn, rvalue, avalue, closure);
765*1fd5a2e1SPrashanth Swaminathan }
766*1fd5a2e1SPrashanth Swaminathan #endif /* FFI_GO_CLOSURES */
767*1fd5a2e1SPrashanth Swaminathan 
768*1fd5a2e1SPrashanth Swaminathan /* Build a trampoline.  */
769*1fd5a2e1SPrashanth Swaminathan 
770*1fd5a2e1SPrashanth Swaminathan extern void ffi_closure_SYSV (void) FFI_HIDDEN;
771*1fd5a2e1SPrashanth Swaminathan extern void ffi_closure_SYSV_V (void) FFI_HIDDEN;
772*1fd5a2e1SPrashanth Swaminathan 
773*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)774*1fd5a2e1SPrashanth Swaminathan ffi_prep_closure_loc (ffi_closure *closure,
775*1fd5a2e1SPrashanth Swaminathan                       ffi_cif* cif,
776*1fd5a2e1SPrashanth Swaminathan                       void (*fun)(ffi_cif*,void*,void**,void*),
777*1fd5a2e1SPrashanth Swaminathan                       void *user_data,
778*1fd5a2e1SPrashanth Swaminathan                       void *codeloc)
779*1fd5a2e1SPrashanth Swaminathan {
780*1fd5a2e1SPrashanth Swaminathan   if (cif->abi != FFI_SYSV)
781*1fd5a2e1SPrashanth Swaminathan     return FFI_BAD_ABI;
782*1fd5a2e1SPrashanth Swaminathan 
783*1fd5a2e1SPrashanth Swaminathan   void (*start)(void);
784*1fd5a2e1SPrashanth Swaminathan 
785*1fd5a2e1SPrashanth Swaminathan   if (cif->flags & AARCH64_FLAG_ARG_V)
786*1fd5a2e1SPrashanth Swaminathan     start = ffi_closure_SYSV_V;
787*1fd5a2e1SPrashanth Swaminathan   else
788*1fd5a2e1SPrashanth Swaminathan     start = ffi_closure_SYSV;
789*1fd5a2e1SPrashanth Swaminathan 
790*1fd5a2e1SPrashanth Swaminathan #if FFI_EXEC_TRAMPOLINE_TABLE
791*1fd5a2e1SPrashanth Swaminathan #ifdef __MACH__
792*1fd5a2e1SPrashanth Swaminathan   void **config = (void **)((uint8_t *)codeloc - PAGE_MAX_SIZE);
793*1fd5a2e1SPrashanth Swaminathan   config[0] = closure;
794*1fd5a2e1SPrashanth Swaminathan   config[1] = start;
795*1fd5a2e1SPrashanth Swaminathan #endif
796*1fd5a2e1SPrashanth Swaminathan #else
797*1fd5a2e1SPrashanth Swaminathan   static const unsigned char trampoline[16] = {
798*1fd5a2e1SPrashanth Swaminathan     0x90, 0x00, 0x00, 0x58,	/* ldr	x16, tramp+16	*/
799*1fd5a2e1SPrashanth Swaminathan     0xf1, 0xff, 0xff, 0x10,	/* adr	x17, tramp+0	*/
800*1fd5a2e1SPrashanth Swaminathan     0x00, 0x02, 0x1f, 0xd6	/* br	x16		*/
801*1fd5a2e1SPrashanth Swaminathan   };
802*1fd5a2e1SPrashanth Swaminathan   char *tramp = closure->tramp;
803*1fd5a2e1SPrashanth Swaminathan 
804*1fd5a2e1SPrashanth Swaminathan   memcpy (tramp, trampoline, sizeof(trampoline));
805*1fd5a2e1SPrashanth Swaminathan 
806*1fd5a2e1SPrashanth Swaminathan   *(UINT64 *)(tramp + 16) = (uintptr_t)start;
807*1fd5a2e1SPrashanth Swaminathan 
808*1fd5a2e1SPrashanth Swaminathan   ffi_clear_cache(tramp, tramp + FFI_TRAMPOLINE_SIZE);
809*1fd5a2e1SPrashanth Swaminathan 
810*1fd5a2e1SPrashanth Swaminathan   /* Also flush the cache for code mapping.  */
811*1fd5a2e1SPrashanth Swaminathan #ifdef _M_ARM64
812*1fd5a2e1SPrashanth Swaminathan   // Not using dlmalloc.c for Windows ARM64 builds
813*1fd5a2e1SPrashanth Swaminathan   // so calling ffi_data_to_code_pointer() isn't necessary
814*1fd5a2e1SPrashanth Swaminathan   unsigned char *tramp_code = tramp;
815*1fd5a2e1SPrashanth Swaminathan   #else
816*1fd5a2e1SPrashanth Swaminathan   unsigned char *tramp_code = ffi_data_to_code_pointer (tramp);
817*1fd5a2e1SPrashanth Swaminathan   #endif
818*1fd5a2e1SPrashanth Swaminathan   ffi_clear_cache (tramp_code, tramp_code + FFI_TRAMPOLINE_SIZE);
819*1fd5a2e1SPrashanth Swaminathan #endif
820*1fd5a2e1SPrashanth Swaminathan 
821*1fd5a2e1SPrashanth Swaminathan   closure->cif = cif;
822*1fd5a2e1SPrashanth Swaminathan   closure->fun = fun;
823*1fd5a2e1SPrashanth Swaminathan   closure->user_data = user_data;
824*1fd5a2e1SPrashanth Swaminathan 
825*1fd5a2e1SPrashanth Swaminathan   return FFI_OK;
826*1fd5a2e1SPrashanth Swaminathan }
827*1fd5a2e1SPrashanth Swaminathan 
828*1fd5a2e1SPrashanth Swaminathan #ifdef FFI_GO_CLOSURES
829*1fd5a2e1SPrashanth Swaminathan extern void ffi_go_closure_SYSV (void) FFI_HIDDEN;
830*1fd5a2e1SPrashanth Swaminathan extern void ffi_go_closure_SYSV_V (void) FFI_HIDDEN;
831*1fd5a2e1SPrashanth Swaminathan 
832*1fd5a2e1SPrashanth Swaminathan ffi_status
ffi_prep_go_closure(ffi_go_closure * closure,ffi_cif * cif,void (* fun)(ffi_cif *,void *,void **,void *))833*1fd5a2e1SPrashanth Swaminathan ffi_prep_go_closure (ffi_go_closure *closure, ffi_cif* cif,
834*1fd5a2e1SPrashanth Swaminathan                      void (*fun)(ffi_cif*,void*,void**,void*))
835*1fd5a2e1SPrashanth Swaminathan {
836*1fd5a2e1SPrashanth Swaminathan   void (*start)(void);
837*1fd5a2e1SPrashanth Swaminathan 
838*1fd5a2e1SPrashanth Swaminathan   if (cif->abi != FFI_SYSV)
839*1fd5a2e1SPrashanth Swaminathan     return FFI_BAD_ABI;
840*1fd5a2e1SPrashanth Swaminathan 
841*1fd5a2e1SPrashanth Swaminathan   if (cif->flags & AARCH64_FLAG_ARG_V)
842*1fd5a2e1SPrashanth Swaminathan     start = ffi_go_closure_SYSV_V;
843*1fd5a2e1SPrashanth Swaminathan   else
844*1fd5a2e1SPrashanth Swaminathan     start = ffi_go_closure_SYSV;
845*1fd5a2e1SPrashanth Swaminathan 
846*1fd5a2e1SPrashanth Swaminathan   closure->tramp = start;
847*1fd5a2e1SPrashanth Swaminathan   closure->cif = cif;
848*1fd5a2e1SPrashanth Swaminathan   closure->fun = fun;
849*1fd5a2e1SPrashanth Swaminathan 
850*1fd5a2e1SPrashanth Swaminathan   return FFI_OK;
851*1fd5a2e1SPrashanth Swaminathan }
852*1fd5a2e1SPrashanth Swaminathan #endif /* FFI_GO_CLOSURES */
853*1fd5a2e1SPrashanth Swaminathan 
854*1fd5a2e1SPrashanth Swaminathan /* Primary handler to setup and invoke a function within a closure.
855*1fd5a2e1SPrashanth Swaminathan 
856*1fd5a2e1SPrashanth Swaminathan    A closure when invoked enters via the assembler wrapper
857*1fd5a2e1SPrashanth Swaminathan    ffi_closure_SYSV(). The wrapper allocates a call context on the
858*1fd5a2e1SPrashanth Swaminathan    stack, saves the interesting registers (from the perspective of
859*1fd5a2e1SPrashanth Swaminathan    the calling convention) into the context then passes control to
860*1fd5a2e1SPrashanth Swaminathan    ffi_closure_SYSV_inner() passing the saved context and a pointer to
861*1fd5a2e1SPrashanth Swaminathan    the stack at the point ffi_closure_SYSV() was invoked.
862*1fd5a2e1SPrashanth Swaminathan 
863*1fd5a2e1SPrashanth Swaminathan    On the return path the assembler wrapper will reload call context
864*1fd5a2e1SPrashanth Swaminathan    registers.
865*1fd5a2e1SPrashanth Swaminathan 
866*1fd5a2e1SPrashanth Swaminathan    ffi_closure_SYSV_inner() marshalls the call context into ffi value
867*1fd5a2e1SPrashanth Swaminathan    descriptors, invokes the wrapped function, then marshalls the return
868*1fd5a2e1SPrashanth Swaminathan    value back into the call context.  */
869*1fd5a2e1SPrashanth Swaminathan 
870*1fd5a2e1SPrashanth Swaminathan int FFI_HIDDEN
ffi_closure_SYSV_inner(ffi_cif * cif,void (* fun)(ffi_cif *,void *,void **,void *),void * user_data,struct call_context * context,void * stack,void * rvalue,void * struct_rvalue)871*1fd5a2e1SPrashanth Swaminathan ffi_closure_SYSV_inner (ffi_cif *cif,
872*1fd5a2e1SPrashanth Swaminathan 			void (*fun)(ffi_cif*,void*,void**,void*),
873*1fd5a2e1SPrashanth Swaminathan 			void *user_data,
874*1fd5a2e1SPrashanth Swaminathan 			struct call_context *context,
875*1fd5a2e1SPrashanth Swaminathan 			void *stack, void *rvalue, void *struct_rvalue)
876*1fd5a2e1SPrashanth Swaminathan {
877*1fd5a2e1SPrashanth Swaminathan   void **avalue = (void**) alloca (cif->nargs * sizeof (void*));
878*1fd5a2e1SPrashanth Swaminathan   int i, h, nargs, flags;
879*1fd5a2e1SPrashanth Swaminathan   struct arg_state state;
880*1fd5a2e1SPrashanth Swaminathan 
881*1fd5a2e1SPrashanth Swaminathan   arg_init (&state);
882*1fd5a2e1SPrashanth Swaminathan 
883*1fd5a2e1SPrashanth Swaminathan   for (i = 0, nargs = cif->nargs; i < nargs; i++)
884*1fd5a2e1SPrashanth Swaminathan     {
885*1fd5a2e1SPrashanth Swaminathan       ffi_type *ty = cif->arg_types[i];
886*1fd5a2e1SPrashanth Swaminathan       int t = ty->type;
887*1fd5a2e1SPrashanth Swaminathan       size_t n, s = ty->size;
888*1fd5a2e1SPrashanth Swaminathan 
889*1fd5a2e1SPrashanth Swaminathan       switch (t)
890*1fd5a2e1SPrashanth Swaminathan 	{
891*1fd5a2e1SPrashanth Swaminathan 	case FFI_TYPE_VOID:
892*1fd5a2e1SPrashanth Swaminathan 	  FFI_ASSERT (0);
893*1fd5a2e1SPrashanth Swaminathan 	  break;
894*1fd5a2e1SPrashanth Swaminathan 
895*1fd5a2e1SPrashanth Swaminathan 	case FFI_TYPE_INT:
896*1fd5a2e1SPrashanth Swaminathan 	case FFI_TYPE_UINT8:
897*1fd5a2e1SPrashanth Swaminathan 	case FFI_TYPE_SINT8:
898*1fd5a2e1SPrashanth Swaminathan 	case FFI_TYPE_UINT16:
899*1fd5a2e1SPrashanth Swaminathan 	case FFI_TYPE_SINT16:
900*1fd5a2e1SPrashanth Swaminathan 	case FFI_TYPE_UINT32:
901*1fd5a2e1SPrashanth Swaminathan 	case FFI_TYPE_SINT32:
902*1fd5a2e1SPrashanth Swaminathan 	case FFI_TYPE_UINT64:
903*1fd5a2e1SPrashanth Swaminathan 	case FFI_TYPE_SINT64:
904*1fd5a2e1SPrashanth Swaminathan 	case FFI_TYPE_POINTER:
905*1fd5a2e1SPrashanth Swaminathan 	  avalue[i] = allocate_int_to_reg_or_stack (context, &state, stack, s);
906*1fd5a2e1SPrashanth Swaminathan 	  break;
907*1fd5a2e1SPrashanth Swaminathan 
908*1fd5a2e1SPrashanth Swaminathan 	case FFI_TYPE_FLOAT:
909*1fd5a2e1SPrashanth Swaminathan 	case FFI_TYPE_DOUBLE:
910*1fd5a2e1SPrashanth Swaminathan 	case FFI_TYPE_LONGDOUBLE:
911*1fd5a2e1SPrashanth Swaminathan 	case FFI_TYPE_STRUCT:
912*1fd5a2e1SPrashanth Swaminathan 	case FFI_TYPE_COMPLEX:
913*1fd5a2e1SPrashanth Swaminathan 	  h = is_vfp_type (ty);
914*1fd5a2e1SPrashanth Swaminathan 	  if (h)
915*1fd5a2e1SPrashanth Swaminathan 	    {
916*1fd5a2e1SPrashanth Swaminathan 	      n = 4 - (h & 3);
917*1fd5a2e1SPrashanth Swaminathan #ifdef _M_ARM64  /* for handling armasm calling convention */
918*1fd5a2e1SPrashanth Swaminathan               if (cif->is_variadic)
919*1fd5a2e1SPrashanth Swaminathan                 {
920*1fd5a2e1SPrashanth Swaminathan                   if (state.ngrn + n <= N_X_ARG_REG)
921*1fd5a2e1SPrashanth Swaminathan                     {
922*1fd5a2e1SPrashanth Swaminathan                       void *reg = &context->x[state.ngrn];
923*1fd5a2e1SPrashanth Swaminathan                       state.ngrn += (unsigned int)n;
924*1fd5a2e1SPrashanth Swaminathan 
925*1fd5a2e1SPrashanth Swaminathan                       /* Eeek! We need a pointer to the structure, however the
926*1fd5a2e1SPrashanth Swaminathan                        homogeneous float elements are being passed in individual
927*1fd5a2e1SPrashanth Swaminathan                        registers, therefore for float and double the structure
928*1fd5a2e1SPrashanth Swaminathan                        is not represented as a contiguous sequence of bytes in
929*1fd5a2e1SPrashanth Swaminathan                        our saved register context.  We don't need the original
930*1fd5a2e1SPrashanth Swaminathan                        contents of the register storage, so we reformat the
931*1fd5a2e1SPrashanth Swaminathan                        structure into the same memory.  */
932*1fd5a2e1SPrashanth Swaminathan                       avalue[i] = compress_hfa_type(reg, reg, h);
933*1fd5a2e1SPrashanth Swaminathan                     }
934*1fd5a2e1SPrashanth Swaminathan                   else
935*1fd5a2e1SPrashanth Swaminathan                     {
936*1fd5a2e1SPrashanth Swaminathan                       state.ngrn = N_X_ARG_REG;
937*1fd5a2e1SPrashanth Swaminathan                       state.nsrn = N_V_ARG_REG;
938*1fd5a2e1SPrashanth Swaminathan                       avalue[i] = allocate_to_stack(&state, stack,
939*1fd5a2e1SPrashanth Swaminathan                              ty->alignment, s);
940*1fd5a2e1SPrashanth Swaminathan                     }
941*1fd5a2e1SPrashanth Swaminathan                 }
942*1fd5a2e1SPrashanth Swaminathan               else
943*1fd5a2e1SPrashanth Swaminathan                 {
944*1fd5a2e1SPrashanth Swaminathan #endif  /* for handling armasm calling convention */
945*1fd5a2e1SPrashanth Swaminathan                   if (state.nsrn + n <= N_V_ARG_REG)
946*1fd5a2e1SPrashanth Swaminathan                     {
947*1fd5a2e1SPrashanth Swaminathan                       void *reg = &context->v[state.nsrn];
948*1fd5a2e1SPrashanth Swaminathan                       state.nsrn += (unsigned int)n;
949*1fd5a2e1SPrashanth Swaminathan                       avalue[i] = compress_hfa_type(reg, reg, h);
950*1fd5a2e1SPrashanth Swaminathan                     }
951*1fd5a2e1SPrashanth Swaminathan                   else
952*1fd5a2e1SPrashanth Swaminathan                     {
953*1fd5a2e1SPrashanth Swaminathan                       state.nsrn = N_V_ARG_REG;
954*1fd5a2e1SPrashanth Swaminathan                       avalue[i] = allocate_to_stack(&state, stack,
955*1fd5a2e1SPrashanth Swaminathan                                                    ty->alignment, s);
956*1fd5a2e1SPrashanth Swaminathan                     }
957*1fd5a2e1SPrashanth Swaminathan #ifdef _M_ARM64  /* for handling armasm calling convention */
958*1fd5a2e1SPrashanth Swaminathan                 }
959*1fd5a2e1SPrashanth Swaminathan #endif  /* for handling armasm calling convention */
960*1fd5a2e1SPrashanth Swaminathan             }
961*1fd5a2e1SPrashanth Swaminathan           else if (s > 16)
962*1fd5a2e1SPrashanth Swaminathan             {
963*1fd5a2e1SPrashanth Swaminathan               /* Replace Composite type of size greater than 16 with a
964*1fd5a2e1SPrashanth Swaminathan                   pointer.  */
965*1fd5a2e1SPrashanth Swaminathan               avalue[i] = *(void **)
966*1fd5a2e1SPrashanth Swaminathan               allocate_int_to_reg_or_stack (context, &state, stack,
967*1fd5a2e1SPrashanth Swaminathan                                          sizeof (void *));
968*1fd5a2e1SPrashanth Swaminathan             }
969*1fd5a2e1SPrashanth Swaminathan           else
970*1fd5a2e1SPrashanth Swaminathan             {
971*1fd5a2e1SPrashanth Swaminathan               n = (s + 7) / 8;
972*1fd5a2e1SPrashanth Swaminathan               if (state.ngrn + n <= N_X_ARG_REG)
973*1fd5a2e1SPrashanth Swaminathan                 {
974*1fd5a2e1SPrashanth Swaminathan                   avalue[i] = &context->x[state.ngrn];
975*1fd5a2e1SPrashanth Swaminathan                   state.ngrn += (unsigned int)n;
976*1fd5a2e1SPrashanth Swaminathan                 }
977*1fd5a2e1SPrashanth Swaminathan               else
978*1fd5a2e1SPrashanth Swaminathan                 {
979*1fd5a2e1SPrashanth Swaminathan                   state.ngrn = N_X_ARG_REG;
980*1fd5a2e1SPrashanth Swaminathan                   avalue[i] = allocate_to_stack(&state, stack,
981*1fd5a2e1SPrashanth Swaminathan                                            ty->alignment, s);
982*1fd5a2e1SPrashanth Swaminathan                 }
983*1fd5a2e1SPrashanth Swaminathan             }
984*1fd5a2e1SPrashanth Swaminathan           break;
985*1fd5a2e1SPrashanth Swaminathan 
986*1fd5a2e1SPrashanth Swaminathan         default:
987*1fd5a2e1SPrashanth Swaminathan           abort();
988*1fd5a2e1SPrashanth Swaminathan       }
989*1fd5a2e1SPrashanth Swaminathan 
990*1fd5a2e1SPrashanth Swaminathan #if defined (__APPLE__)
991*1fd5a2e1SPrashanth Swaminathan       if (i + 1 == cif->aarch64_nfixedargs)
992*1fd5a2e1SPrashanth Swaminathan 	{
993*1fd5a2e1SPrashanth Swaminathan 	  state.ngrn = N_X_ARG_REG;
994*1fd5a2e1SPrashanth Swaminathan 	  state.nsrn = N_V_ARG_REG;
995*1fd5a2e1SPrashanth Swaminathan 	  state.allocating_variadic = 1;
996*1fd5a2e1SPrashanth Swaminathan 	}
997*1fd5a2e1SPrashanth Swaminathan #endif
998*1fd5a2e1SPrashanth Swaminathan     }
999*1fd5a2e1SPrashanth Swaminathan 
1000*1fd5a2e1SPrashanth Swaminathan   flags = cif->flags;
1001*1fd5a2e1SPrashanth Swaminathan   if (flags & AARCH64_RET_IN_MEM)
1002*1fd5a2e1SPrashanth Swaminathan     rvalue = struct_rvalue;
1003*1fd5a2e1SPrashanth Swaminathan 
1004*1fd5a2e1SPrashanth Swaminathan   fun (cif, rvalue, avalue, user_data);
1005*1fd5a2e1SPrashanth Swaminathan 
1006*1fd5a2e1SPrashanth Swaminathan   return flags;
1007*1fd5a2e1SPrashanth Swaminathan }
1008*1fd5a2e1SPrashanth Swaminathan 
1009*1fd5a2e1SPrashanth Swaminathan #endif /* (__aarch64__) || defined(__arm64__)|| defined (_M_ARM64)*/
1010