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