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