1*1fd5a2e1SPrashanth Swaminathan /* -----------------------------------------------------------------------
2*1fd5a2e1SPrashanth Swaminathan prep_cif.c - Copyright (c) 2011, 2012 Anthony Green
3*1fd5a2e1SPrashanth Swaminathan Copyright (c) 1996, 1998, 2007 Red Hat, Inc.
4*1fd5a2e1SPrashanth Swaminathan
5*1fd5a2e1SPrashanth Swaminathan Permission is hereby granted, free of charge, to any person obtaining
6*1fd5a2e1SPrashanth Swaminathan a copy of this software and associated documentation files (the
7*1fd5a2e1SPrashanth Swaminathan ``Software''), to deal in the Software without restriction, including
8*1fd5a2e1SPrashanth Swaminathan without limitation the rights to use, copy, modify, merge, publish,
9*1fd5a2e1SPrashanth Swaminathan distribute, sublicense, and/or sell copies of the Software, and to
10*1fd5a2e1SPrashanth Swaminathan permit persons to whom the Software is furnished to do so, subject to
11*1fd5a2e1SPrashanth Swaminathan the following conditions:
12*1fd5a2e1SPrashanth Swaminathan
13*1fd5a2e1SPrashanth Swaminathan The above copyright notice and this permission notice shall be included
14*1fd5a2e1SPrashanth Swaminathan in all copies or substantial portions of the Software.
15*1fd5a2e1SPrashanth Swaminathan
16*1fd5a2e1SPrashanth Swaminathan THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND,
17*1fd5a2e1SPrashanth Swaminathan EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18*1fd5a2e1SPrashanth Swaminathan MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19*1fd5a2e1SPrashanth Swaminathan NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
20*1fd5a2e1SPrashanth Swaminathan HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
21*1fd5a2e1SPrashanth Swaminathan WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22*1fd5a2e1SPrashanth Swaminathan OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
23*1fd5a2e1SPrashanth Swaminathan DEALINGS IN THE SOFTWARE.
24*1fd5a2e1SPrashanth Swaminathan ----------------------------------------------------------------------- */
25*1fd5a2e1SPrashanth Swaminathan
26*1fd5a2e1SPrashanth Swaminathan #include <ffi.h>
27*1fd5a2e1SPrashanth Swaminathan #include <ffi_common.h>
28*1fd5a2e1SPrashanth Swaminathan #include <stdlib.h>
29*1fd5a2e1SPrashanth Swaminathan
30*1fd5a2e1SPrashanth Swaminathan /* Round up to FFI_SIZEOF_ARG. */
31*1fd5a2e1SPrashanth Swaminathan
32*1fd5a2e1SPrashanth Swaminathan #define STACK_ARG_SIZE(x) FFI_ALIGN(x, FFI_SIZEOF_ARG)
33*1fd5a2e1SPrashanth Swaminathan
34*1fd5a2e1SPrashanth Swaminathan /* Perform machine independent initialization of aggregate type
35*1fd5a2e1SPrashanth Swaminathan specifications. */
36*1fd5a2e1SPrashanth Swaminathan
initialize_aggregate(ffi_type * arg,size_t * offsets)37*1fd5a2e1SPrashanth Swaminathan static ffi_status initialize_aggregate(ffi_type *arg, size_t *offsets)
38*1fd5a2e1SPrashanth Swaminathan {
39*1fd5a2e1SPrashanth Swaminathan ffi_type **ptr;
40*1fd5a2e1SPrashanth Swaminathan
41*1fd5a2e1SPrashanth Swaminathan if (UNLIKELY(arg == NULL || arg->elements == NULL))
42*1fd5a2e1SPrashanth Swaminathan return FFI_BAD_TYPEDEF;
43*1fd5a2e1SPrashanth Swaminathan
44*1fd5a2e1SPrashanth Swaminathan arg->size = 0;
45*1fd5a2e1SPrashanth Swaminathan arg->alignment = 0;
46*1fd5a2e1SPrashanth Swaminathan
47*1fd5a2e1SPrashanth Swaminathan ptr = &(arg->elements[0]);
48*1fd5a2e1SPrashanth Swaminathan
49*1fd5a2e1SPrashanth Swaminathan if (UNLIKELY(ptr == 0))
50*1fd5a2e1SPrashanth Swaminathan return FFI_BAD_TYPEDEF;
51*1fd5a2e1SPrashanth Swaminathan
52*1fd5a2e1SPrashanth Swaminathan while ((*ptr) != NULL)
53*1fd5a2e1SPrashanth Swaminathan {
54*1fd5a2e1SPrashanth Swaminathan if (UNLIKELY(((*ptr)->size == 0)
55*1fd5a2e1SPrashanth Swaminathan && (initialize_aggregate((*ptr), NULL) != FFI_OK)))
56*1fd5a2e1SPrashanth Swaminathan return FFI_BAD_TYPEDEF;
57*1fd5a2e1SPrashanth Swaminathan
58*1fd5a2e1SPrashanth Swaminathan /* Perform a sanity check on the argument type */
59*1fd5a2e1SPrashanth Swaminathan FFI_ASSERT_VALID_TYPE(*ptr);
60*1fd5a2e1SPrashanth Swaminathan
61*1fd5a2e1SPrashanth Swaminathan arg->size = FFI_ALIGN(arg->size, (*ptr)->alignment);
62*1fd5a2e1SPrashanth Swaminathan if (offsets)
63*1fd5a2e1SPrashanth Swaminathan *offsets++ = arg->size;
64*1fd5a2e1SPrashanth Swaminathan arg->size += (*ptr)->size;
65*1fd5a2e1SPrashanth Swaminathan
66*1fd5a2e1SPrashanth Swaminathan arg->alignment = (arg->alignment > (*ptr)->alignment) ?
67*1fd5a2e1SPrashanth Swaminathan arg->alignment : (*ptr)->alignment;
68*1fd5a2e1SPrashanth Swaminathan
69*1fd5a2e1SPrashanth Swaminathan ptr++;
70*1fd5a2e1SPrashanth Swaminathan }
71*1fd5a2e1SPrashanth Swaminathan
72*1fd5a2e1SPrashanth Swaminathan /* Structure size includes tail padding. This is important for
73*1fd5a2e1SPrashanth Swaminathan structures that fit in one register on ABIs like the PowerPC64
74*1fd5a2e1SPrashanth Swaminathan Linux ABI that right justify small structs in a register.
75*1fd5a2e1SPrashanth Swaminathan It's also needed for nested structure layout, for example
76*1fd5a2e1SPrashanth Swaminathan struct A { long a; char b; }; struct B { struct A x; char y; };
77*1fd5a2e1SPrashanth Swaminathan should find y at an offset of 2*sizeof(long) and result in a
78*1fd5a2e1SPrashanth Swaminathan total size of 3*sizeof(long). */
79*1fd5a2e1SPrashanth Swaminathan arg->size = FFI_ALIGN (arg->size, arg->alignment);
80*1fd5a2e1SPrashanth Swaminathan
81*1fd5a2e1SPrashanth Swaminathan /* On some targets, the ABI defines that structures have an additional
82*1fd5a2e1SPrashanth Swaminathan alignment beyond the "natural" one based on their elements. */
83*1fd5a2e1SPrashanth Swaminathan #ifdef FFI_AGGREGATE_ALIGNMENT
84*1fd5a2e1SPrashanth Swaminathan if (FFI_AGGREGATE_ALIGNMENT > arg->alignment)
85*1fd5a2e1SPrashanth Swaminathan arg->alignment = FFI_AGGREGATE_ALIGNMENT;
86*1fd5a2e1SPrashanth Swaminathan #endif
87*1fd5a2e1SPrashanth Swaminathan
88*1fd5a2e1SPrashanth Swaminathan if (arg->size == 0)
89*1fd5a2e1SPrashanth Swaminathan return FFI_BAD_TYPEDEF;
90*1fd5a2e1SPrashanth Swaminathan else
91*1fd5a2e1SPrashanth Swaminathan return FFI_OK;
92*1fd5a2e1SPrashanth Swaminathan }
93*1fd5a2e1SPrashanth Swaminathan
94*1fd5a2e1SPrashanth Swaminathan #ifndef __CRIS__
95*1fd5a2e1SPrashanth Swaminathan /* The CRIS ABI specifies structure elements to have byte
96*1fd5a2e1SPrashanth Swaminathan alignment only, so it completely overrides this functions,
97*1fd5a2e1SPrashanth Swaminathan which assumes "natural" alignment and padding. */
98*1fd5a2e1SPrashanth Swaminathan
99*1fd5a2e1SPrashanth Swaminathan /* Perform machine independent ffi_cif preparation, then call
100*1fd5a2e1SPrashanth Swaminathan machine dependent routine. */
101*1fd5a2e1SPrashanth Swaminathan
102*1fd5a2e1SPrashanth Swaminathan /* For non variadic functions isvariadic should be 0 and
103*1fd5a2e1SPrashanth Swaminathan nfixedargs==ntotalargs.
104*1fd5a2e1SPrashanth Swaminathan
105*1fd5a2e1SPrashanth Swaminathan For variadic calls, isvariadic should be 1 and nfixedargs
106*1fd5a2e1SPrashanth Swaminathan and ntotalargs set as appropriate. nfixedargs must always be >=1 */
107*1fd5a2e1SPrashanth Swaminathan
108*1fd5a2e1SPrashanth Swaminathan
ffi_prep_cif_core(ffi_cif * cif,ffi_abi abi,unsigned int isvariadic,unsigned int nfixedargs,unsigned int ntotalargs,ffi_type * rtype,ffi_type ** atypes)109*1fd5a2e1SPrashanth Swaminathan ffi_status FFI_HIDDEN ffi_prep_cif_core(ffi_cif *cif, ffi_abi abi,
110*1fd5a2e1SPrashanth Swaminathan unsigned int isvariadic,
111*1fd5a2e1SPrashanth Swaminathan unsigned int nfixedargs,
112*1fd5a2e1SPrashanth Swaminathan unsigned int ntotalargs,
113*1fd5a2e1SPrashanth Swaminathan ffi_type *rtype, ffi_type **atypes)
114*1fd5a2e1SPrashanth Swaminathan {
115*1fd5a2e1SPrashanth Swaminathan unsigned bytes = 0;
116*1fd5a2e1SPrashanth Swaminathan unsigned int i;
117*1fd5a2e1SPrashanth Swaminathan ffi_type **ptr;
118*1fd5a2e1SPrashanth Swaminathan
119*1fd5a2e1SPrashanth Swaminathan FFI_ASSERT(cif != NULL);
120*1fd5a2e1SPrashanth Swaminathan FFI_ASSERT((!isvariadic) || (nfixedargs >= 1));
121*1fd5a2e1SPrashanth Swaminathan FFI_ASSERT(nfixedargs <= ntotalargs);
122*1fd5a2e1SPrashanth Swaminathan
123*1fd5a2e1SPrashanth Swaminathan if (! (abi > FFI_FIRST_ABI && abi < FFI_LAST_ABI))
124*1fd5a2e1SPrashanth Swaminathan return FFI_BAD_ABI;
125*1fd5a2e1SPrashanth Swaminathan
126*1fd5a2e1SPrashanth Swaminathan cif->abi = abi;
127*1fd5a2e1SPrashanth Swaminathan cif->arg_types = atypes;
128*1fd5a2e1SPrashanth Swaminathan cif->nargs = ntotalargs;
129*1fd5a2e1SPrashanth Swaminathan cif->rtype = rtype;
130*1fd5a2e1SPrashanth Swaminathan
131*1fd5a2e1SPrashanth Swaminathan cif->flags = 0;
132*1fd5a2e1SPrashanth Swaminathan #ifdef _M_ARM64
133*1fd5a2e1SPrashanth Swaminathan cif->is_variadic = isvariadic;
134*1fd5a2e1SPrashanth Swaminathan #endif
135*1fd5a2e1SPrashanth Swaminathan #if HAVE_LONG_DOUBLE_VARIANT
136*1fd5a2e1SPrashanth Swaminathan ffi_prep_types (abi);
137*1fd5a2e1SPrashanth Swaminathan #endif
138*1fd5a2e1SPrashanth Swaminathan
139*1fd5a2e1SPrashanth Swaminathan /* Initialize the return type if necessary */
140*1fd5a2e1SPrashanth Swaminathan if ((cif->rtype->size == 0)
141*1fd5a2e1SPrashanth Swaminathan && (initialize_aggregate(cif->rtype, NULL) != FFI_OK))
142*1fd5a2e1SPrashanth Swaminathan return FFI_BAD_TYPEDEF;
143*1fd5a2e1SPrashanth Swaminathan
144*1fd5a2e1SPrashanth Swaminathan #ifndef FFI_TARGET_HAS_COMPLEX_TYPE
145*1fd5a2e1SPrashanth Swaminathan if (rtype->type == FFI_TYPE_COMPLEX)
146*1fd5a2e1SPrashanth Swaminathan abort();
147*1fd5a2e1SPrashanth Swaminathan #endif
148*1fd5a2e1SPrashanth Swaminathan /* Perform a sanity check on the return type */
149*1fd5a2e1SPrashanth Swaminathan FFI_ASSERT_VALID_TYPE(cif->rtype);
150*1fd5a2e1SPrashanth Swaminathan
151*1fd5a2e1SPrashanth Swaminathan /* x86, x86-64 and s390 stack space allocation is handled in prep_machdep. */
152*1fd5a2e1SPrashanth Swaminathan #if !defined FFI_TARGET_SPECIFIC_STACK_SPACE_ALLOCATION
153*1fd5a2e1SPrashanth Swaminathan /* Make space for the return structure pointer */
154*1fd5a2e1SPrashanth Swaminathan if (cif->rtype->type == FFI_TYPE_STRUCT
155*1fd5a2e1SPrashanth Swaminathan #ifdef TILE
156*1fd5a2e1SPrashanth Swaminathan && (cif->rtype->size > 10 * FFI_SIZEOF_ARG)
157*1fd5a2e1SPrashanth Swaminathan #endif
158*1fd5a2e1SPrashanth Swaminathan #ifdef XTENSA
159*1fd5a2e1SPrashanth Swaminathan && (cif->rtype->size > 16)
160*1fd5a2e1SPrashanth Swaminathan #endif
161*1fd5a2e1SPrashanth Swaminathan #ifdef NIOS2
162*1fd5a2e1SPrashanth Swaminathan && (cif->rtype->size > 8)
163*1fd5a2e1SPrashanth Swaminathan #endif
164*1fd5a2e1SPrashanth Swaminathan )
165*1fd5a2e1SPrashanth Swaminathan bytes = STACK_ARG_SIZE(sizeof(void*));
166*1fd5a2e1SPrashanth Swaminathan #endif
167*1fd5a2e1SPrashanth Swaminathan
168*1fd5a2e1SPrashanth Swaminathan for (ptr = cif->arg_types, i = cif->nargs; i > 0; i--, ptr++)
169*1fd5a2e1SPrashanth Swaminathan {
170*1fd5a2e1SPrashanth Swaminathan
171*1fd5a2e1SPrashanth Swaminathan /* Initialize any uninitialized aggregate type definitions */
172*1fd5a2e1SPrashanth Swaminathan if (((*ptr)->size == 0)
173*1fd5a2e1SPrashanth Swaminathan && (initialize_aggregate((*ptr), NULL) != FFI_OK))
174*1fd5a2e1SPrashanth Swaminathan return FFI_BAD_TYPEDEF;
175*1fd5a2e1SPrashanth Swaminathan
176*1fd5a2e1SPrashanth Swaminathan #ifndef FFI_TARGET_HAS_COMPLEX_TYPE
177*1fd5a2e1SPrashanth Swaminathan if ((*ptr)->type == FFI_TYPE_COMPLEX)
178*1fd5a2e1SPrashanth Swaminathan abort();
179*1fd5a2e1SPrashanth Swaminathan #endif
180*1fd5a2e1SPrashanth Swaminathan /* Perform a sanity check on the argument type, do this
181*1fd5a2e1SPrashanth Swaminathan check after the initialization. */
182*1fd5a2e1SPrashanth Swaminathan FFI_ASSERT_VALID_TYPE(*ptr);
183*1fd5a2e1SPrashanth Swaminathan
184*1fd5a2e1SPrashanth Swaminathan #if !defined FFI_TARGET_SPECIFIC_STACK_SPACE_ALLOCATION
185*1fd5a2e1SPrashanth Swaminathan {
186*1fd5a2e1SPrashanth Swaminathan /* Add any padding if necessary */
187*1fd5a2e1SPrashanth Swaminathan if (((*ptr)->alignment - 1) & bytes)
188*1fd5a2e1SPrashanth Swaminathan bytes = (unsigned)FFI_ALIGN(bytes, (*ptr)->alignment);
189*1fd5a2e1SPrashanth Swaminathan
190*1fd5a2e1SPrashanth Swaminathan #ifdef TILE
191*1fd5a2e1SPrashanth Swaminathan if (bytes < 10 * FFI_SIZEOF_ARG &&
192*1fd5a2e1SPrashanth Swaminathan bytes + STACK_ARG_SIZE((*ptr)->size) > 10 * FFI_SIZEOF_ARG)
193*1fd5a2e1SPrashanth Swaminathan {
194*1fd5a2e1SPrashanth Swaminathan /* An argument is never split between the 10 parameter
195*1fd5a2e1SPrashanth Swaminathan registers and the stack. */
196*1fd5a2e1SPrashanth Swaminathan bytes = 10 * FFI_SIZEOF_ARG;
197*1fd5a2e1SPrashanth Swaminathan }
198*1fd5a2e1SPrashanth Swaminathan #endif
199*1fd5a2e1SPrashanth Swaminathan #ifdef XTENSA
200*1fd5a2e1SPrashanth Swaminathan if (bytes <= 6*4 && bytes + STACK_ARG_SIZE((*ptr)->size) > 6*4)
201*1fd5a2e1SPrashanth Swaminathan bytes = 6*4;
202*1fd5a2e1SPrashanth Swaminathan #endif
203*1fd5a2e1SPrashanth Swaminathan
204*1fd5a2e1SPrashanth Swaminathan bytes += (unsigned int)STACK_ARG_SIZE((*ptr)->size);
205*1fd5a2e1SPrashanth Swaminathan }
206*1fd5a2e1SPrashanth Swaminathan #endif
207*1fd5a2e1SPrashanth Swaminathan }
208*1fd5a2e1SPrashanth Swaminathan
209*1fd5a2e1SPrashanth Swaminathan cif->bytes = bytes;
210*1fd5a2e1SPrashanth Swaminathan
211*1fd5a2e1SPrashanth Swaminathan /* Perform machine dependent cif processing */
212*1fd5a2e1SPrashanth Swaminathan #ifdef FFI_TARGET_SPECIFIC_VARIADIC
213*1fd5a2e1SPrashanth Swaminathan if (isvariadic)
214*1fd5a2e1SPrashanth Swaminathan return ffi_prep_cif_machdep_var(cif, nfixedargs, ntotalargs);
215*1fd5a2e1SPrashanth Swaminathan #endif
216*1fd5a2e1SPrashanth Swaminathan
217*1fd5a2e1SPrashanth Swaminathan return ffi_prep_cif_machdep(cif);
218*1fd5a2e1SPrashanth Swaminathan }
219*1fd5a2e1SPrashanth Swaminathan #endif /* not __CRIS__ */
220*1fd5a2e1SPrashanth Swaminathan
ffi_prep_cif(ffi_cif * cif,ffi_abi abi,unsigned int nargs,ffi_type * rtype,ffi_type ** atypes)221*1fd5a2e1SPrashanth Swaminathan ffi_status ffi_prep_cif(ffi_cif *cif, ffi_abi abi, unsigned int nargs,
222*1fd5a2e1SPrashanth Swaminathan ffi_type *rtype, ffi_type **atypes)
223*1fd5a2e1SPrashanth Swaminathan {
224*1fd5a2e1SPrashanth Swaminathan return ffi_prep_cif_core(cif, abi, 0, nargs, nargs, rtype, atypes);
225*1fd5a2e1SPrashanth Swaminathan }
226*1fd5a2e1SPrashanth Swaminathan
ffi_prep_cif_var(ffi_cif * cif,ffi_abi abi,unsigned int nfixedargs,unsigned int ntotalargs,ffi_type * rtype,ffi_type ** atypes)227*1fd5a2e1SPrashanth Swaminathan ffi_status ffi_prep_cif_var(ffi_cif *cif,
228*1fd5a2e1SPrashanth Swaminathan ffi_abi abi,
229*1fd5a2e1SPrashanth Swaminathan unsigned int nfixedargs,
230*1fd5a2e1SPrashanth Swaminathan unsigned int ntotalargs,
231*1fd5a2e1SPrashanth Swaminathan ffi_type *rtype,
232*1fd5a2e1SPrashanth Swaminathan ffi_type **atypes)
233*1fd5a2e1SPrashanth Swaminathan {
234*1fd5a2e1SPrashanth Swaminathan return ffi_prep_cif_core(cif, abi, 1, nfixedargs, ntotalargs, rtype, atypes);
235*1fd5a2e1SPrashanth Swaminathan }
236*1fd5a2e1SPrashanth Swaminathan
237*1fd5a2e1SPrashanth Swaminathan #if FFI_CLOSURES
238*1fd5a2e1SPrashanth Swaminathan
239*1fd5a2e1SPrashanth Swaminathan ffi_status
ffi_prep_closure(ffi_closure * closure,ffi_cif * cif,void (* fun)(ffi_cif *,void *,void **,void *),void * user_data)240*1fd5a2e1SPrashanth Swaminathan ffi_prep_closure (ffi_closure* closure,
241*1fd5a2e1SPrashanth Swaminathan ffi_cif* cif,
242*1fd5a2e1SPrashanth Swaminathan void (*fun)(ffi_cif*,void*,void**,void*),
243*1fd5a2e1SPrashanth Swaminathan void *user_data)
244*1fd5a2e1SPrashanth Swaminathan {
245*1fd5a2e1SPrashanth Swaminathan return ffi_prep_closure_loc (closure, cif, fun, user_data, closure);
246*1fd5a2e1SPrashanth Swaminathan }
247*1fd5a2e1SPrashanth Swaminathan
248*1fd5a2e1SPrashanth Swaminathan #endif
249*1fd5a2e1SPrashanth Swaminathan
250*1fd5a2e1SPrashanth Swaminathan ffi_status
ffi_get_struct_offsets(ffi_abi abi,ffi_type * struct_type,size_t * offsets)251*1fd5a2e1SPrashanth Swaminathan ffi_get_struct_offsets (ffi_abi abi, ffi_type *struct_type, size_t *offsets)
252*1fd5a2e1SPrashanth Swaminathan {
253*1fd5a2e1SPrashanth Swaminathan if (! (abi > FFI_FIRST_ABI && abi < FFI_LAST_ABI))
254*1fd5a2e1SPrashanth Swaminathan return FFI_BAD_ABI;
255*1fd5a2e1SPrashanth Swaminathan if (struct_type->type != FFI_TYPE_STRUCT)
256*1fd5a2e1SPrashanth Swaminathan return FFI_BAD_TYPEDEF;
257*1fd5a2e1SPrashanth Swaminathan
258*1fd5a2e1SPrashanth Swaminathan #if HAVE_LONG_DOUBLE_VARIANT
259*1fd5a2e1SPrashanth Swaminathan ffi_prep_types (abi);
260*1fd5a2e1SPrashanth Swaminathan #endif
261*1fd5a2e1SPrashanth Swaminathan
262*1fd5a2e1SPrashanth Swaminathan return initialize_aggregate(struct_type, offsets);
263*1fd5a2e1SPrashanth Swaminathan }
264