Ruby: ext/fiddle/libffi-3.2.1/src/arm/ffi.c Source File

Ruby 3.0.5p211 (2022-11-24 revision ba5cf0f7c52d4d35cc6a173c89eda98ceffa2dcf)

ffi.c
Go to the documentation of this file.
1/* -----------------------------------------------------------------------
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.
7
8 ARM Foreign Function Interface
9
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
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.
29 ----------------------------------------------------------------------- */
30
31#include <ffi.h>
32#include <ffi_common.h>
33
34#include <stdlib.h>
35
36/* Forward declares. */
37static int vfp_type_p (ffi_type *);
38static void layout_vfp_args (ffi_cif *);
39
40int ffi_prep_args_SYSV(char *stack, extended_cif *ecif, float *vfp_space);
41int ffi_prep_args_VFP(char *stack, extended_cif *ecif, float *vfp_space);
42
43static char* ffi_align(ffi_type **p_arg, char *argp)
44{
45 /* Align if necessary */
46 register size_t alignment = (*p_arg)->alignment;
47 if (alignment < 4)
48 {
49 alignment = 4;
50 }
51#ifdef _WIN32_WCE
52 if (alignment > 4)
53 {
54 alignment = 4;
55 }
56#endif
57 if ((alignment - 1) & (unsigned) argp)
58 {
59 argp = (char *) ALIGN(argp, alignment);
60 }
61
62 if ((*p_arg)->type == FFI_TYPE_STRUCT)
63 {
64 argp = (char *) ALIGN(argp, 4);
65 }
66 return argp;
67}
68
69static size_t ffi_put_arg(ffi_type **arg_type, void **arg, char *stack)
70{
71 register char* argp = stack;
72 register ffi_type **p_arg = arg_type;
73 register void **p_argv = arg;
74 register size_t z = (*p_arg)->size;
75 if (z < sizeof(int))
76 {
77 z = sizeof(int);
78 switch ((*p_arg)->type)
79 {
80 case FFI_TYPE_SINT8:
81 *(signed int *) argp = (signed int)*(SINT8 *)(* p_argv);
82 break;
83
84 case FFI_TYPE_UINT8:
85 *(unsigned int *) argp = (unsigned int)*(UINT8 *)(* p_argv);
86 break;
87
88 case FFI_TYPE_SINT16:
89 *(signed int *) argp = (signed int)*(SINT16 *)(* p_argv);
90 break;
91
92 case FFI_TYPE_UINT16:
93 *(unsigned int *) argp = (unsigned int)*(UINT16 *)(* p_argv);
94 break;
95
96 case FFI_TYPE_STRUCT:
97 memcpy(argp, *p_argv, (*p_arg)->size);
98 break;
99
100 default:
101 FFI_ASSERT(0);
102 }
103 }
104 else if (z == sizeof(int))
105 {
106 if ((*p_arg)->type == FFI_TYPE_FLOAT)
107 *(float *) argp = *(float *)(* p_argv);
108 else
109 *(unsigned int *) argp = (unsigned int)*(UINT32 *)(* p_argv);
110 }
111 else if (z == sizeof(double) && (*p_arg)->type == FFI_TYPE_DOUBLE)
112 {
113 *(double *) argp = *(double *)(* p_argv);
114 }
115 else
116 {
117 memcpy(argp, *p_argv, z);
118 }
119 return z;
120}
121/* ffi_prep_args is called by the assembly routine once stack space
122 has been allocated for the function's arguments
123
124 The vfp_space parameter is the load area for VFP regs, the return
125 value is cif->vfp_used (word bitset of VFP regs used for passing
126 arguments). These are only used for the VFP hard-float ABI.
127*/
128 int ffi_prep_args_SYSV(char *stack, extended_cif *ecif, float *vfp_space)
129{
130 register unsigned int i;
131 register void **p_argv;
132 register char *argp;
133 register ffi_type **p_arg;
134 argp = stack;
135
136
137 if ( ecif->cif->flags == FFI_TYPE_STRUCT ) {
138 *(void **) argp = ecif->rvalue;
139 argp += 4;
140 }
141
142 p_argv = ecif->avalue;
143
144 for (i = ecif->cif->nargs, p_arg = ecif->cif->arg_types;
145 (i != 0);
146 i--, p_arg++, p_argv++)
147 {
148 argp = ffi_align(p_arg, argp);
149 argp += ffi_put_arg(p_arg, p_argv, argp);
150 }
151
152 return 0;
153}
154
155 int ffi_prep_args_VFP(char *stack, extended_cif *ecif, float *vfp_space)
156{
157 register unsigned int i, vi = 0;
158 register void **p_argv;
159 register char *argp, *regp, *eo_regp;
160 register ffi_type **p_arg;
161 char stack_used = 0;
162 char done_with_regs = 0;
163 char is_vfp_type;
164
165 // make sure we are using FFI_VFP
166 FFI_ASSERT(ecif->cif->abi == FFI_VFP);
167
168 /* the first 4 words on the stack are used for values passed in core
169 * registers. */
170 regp = stack;
171 eo_regp = argp = regp + 16;
172
173
174 /* if the function returns an FFI_TYPE_STRUCT in memory, that address is
175 * passed in r0 to the function */
176 if ( ecif->cif->flags == FFI_TYPE_STRUCT ) {
177 *(void **) regp = ecif->rvalue;
178 regp += 4;
179 }
180
181 p_argv = ecif->avalue;
182
183 for (i = ecif->cif->nargs, p_arg = ecif->cif->arg_types;
184 (i != 0);
185 i--, p_arg++, p_argv++)
186 {
187 is_vfp_type = vfp_type_p (*p_arg);
188
189 /* Allocated in VFP registers. */
190 if(vi < ecif->cif->vfp_nargs && is_vfp_type)
191 {
192 char *vfp_slot = (char *)(vfp_space + ecif->cif->vfp_args[vi++]);
193 ffi_put_arg(p_arg, p_argv, vfp_slot);
194 continue;
195 }
196 /* Try allocating in core registers. */
197 else if (!done_with_regs && !is_vfp_type)
198 {
199 char *tregp = ffi_align(p_arg, regp);
200 size_t size = (*p_arg)->size;
201 size = (size < 4)? 4 : size; // pad
202 /* Check if there is space left in the aligned register area to place
203 * the argument */
204 if(tregp + size <= eo_regp)
205 {
206 regp = tregp + ffi_put_arg(p_arg, p_argv, tregp);
207 done_with_regs = (regp == argp);
208 // ensure we did not write into the stack area
209 FFI_ASSERT(regp <= argp);
210 continue;
211 }
212 /* In case there are no arguments in the stack area yet,
213 the argument is passed in the remaining core registers and on the
214 stack. */
215 else if (!stack_used)
216 {
217 stack_used = 1;
218 done_with_regs = 1;
219 argp = tregp + ffi_put_arg(p_arg, p_argv, tregp);
220 FFI_ASSERT(eo_regp < argp);
221 continue;
222 }
223 }
224 /* Base case, arguments are passed on the stack */
225 stack_used = 1;
226 argp = ffi_align(p_arg, argp);
227 argp += ffi_put_arg(p_arg, p_argv, argp);
228 }
229 /* Indicate the VFP registers used. */
230 return ecif->cif->vfp_used;
231}
232
233/* Perform machine dependent cif processing */
234ffi_status ffi_prep_cif_machdep(ffi_cif *cif)
235{
236 int type_code;
237 /* Round the stack up to a multiple of 8 bytes. This isn't needed
238 everywhere, but it is on some platforms, and it doesn't harm anything
239 when it isn't needed. */
240 cif->bytes = (cif->bytes + 7) & ~7;
241
242 /* Set the return type flag */
243 switch (cif->rtype->type)
244 {
245 case FFI_TYPE_VOID:
246 case FFI_TYPE_FLOAT:
247 case FFI_TYPE_DOUBLE:
248 cif->flags = (unsigned) cif->rtype->type;
249 break;
250
251 case FFI_TYPE_SINT64:
252 case FFI_TYPE_UINT64:
253 cif->flags = (unsigned) FFI_TYPE_SINT64;
254 break;
255
256 case FFI_TYPE_STRUCT:
257 if (cif->abi == FFI_VFP
258 && (type_code = vfp_type_p (cif->rtype)) != 0)
259 {
260 /* A Composite Type passed in VFP registers, either
261 FFI_TYPE_STRUCT_VFP_FLOAT or FFI_TYPE_STRUCT_VFP_DOUBLE. */
262 cif->flags = (unsigned) type_code;
263 }
264 else if (cif->rtype->size <= 4)
265 /* A Composite Type not larger than 4 bytes is returned in r0. */
266 cif->flags = (unsigned)FFI_TYPE_INT;
267 else
268 /* A Composite Type larger than 4 bytes, or whose size cannot
269 be determined statically ... is stored in memory at an
270 address passed [in r0]. */
271 cif->flags = (unsigned)FFI_TYPE_STRUCT;
272 break;
273
274 default:
275 cif->flags = FFI_TYPE_INT;
276 break;
277 }
278
279 /* Map out the register placements of VFP register args.
280 The VFP hard-float calling conventions are slightly more sophisticated than
281 the base calling conventions, so we do it here instead of in ffi_prep_args(). */
282 if (cif->abi == FFI_VFP)
283 layout_vfp_args (cif);
284
285 return FFI_OK;
286}
287
288/* Perform machine dependent cif processing for variadic calls */
289ffi_status ffi_prep_cif_machdep_var(ffi_cif *cif,
290 unsigned int nfixedargs,
291 unsigned int ntotalargs)
292{
293 /* VFP variadic calls actually use the SYSV ABI */
294 if (cif->abi == FFI_VFP)
295 cif->abi = FFI_SYSV;
296
297 return ffi_prep_cif_machdep(cif);
298}
299
300/* Prototypes for assembly functions, in sysv.S */
301 extern void ffi_call_SYSV (void (*fn)(void), extended_cif *, unsigned, unsigned, unsigned *);
302 extern void ffi_call_VFP (void (*fn)(void), extended_cif *, unsigned, unsigned, unsigned *);
303
304 void ffi_call(ffi_cif *cif, void (*fn)(void), void *rvalue, void **avalue)
305{
306 extended_cif ecif;
307
308 int small_struct = (cif->flags == FFI_TYPE_INT
309 && cif->rtype->type == FFI_TYPE_STRUCT);
310 int vfp_struct = (cif->flags == FFI_TYPE_STRUCT_VFP_FLOAT
311 || cif->flags == FFI_TYPE_STRUCT_VFP_DOUBLE);
312
313 unsigned int temp;
314
315 ecif.cif = cif;
316 ecif.avalue = avalue;
317
318 /* If the return value is a struct and we don't have a return */
319 /* value address then we need to make one */
320
321 if ((rvalue == NULL) &&
322 (cif->flags == FFI_TYPE_STRUCT))
323 {
324 ecif.rvalue = alloca(cif->rtype->size);
325 }
326 else if (small_struct)
327 ecif.rvalue = &temp;
328 else if (vfp_struct)
329 {
330 /* Largest case is double x 4. */
331 ecif.rvalue = alloca(32);
332 }
333 else
334 ecif.rvalue = rvalue;
335
336 switch (cif->abi)
337 {
338 case FFI_SYSV:
339 ffi_call_SYSV (fn, &ecif, cif->bytes, cif->flags, ecif.rvalue);
340 break;
341
342 case FFI_VFP:
343#ifdef __ARM_EABI__
344 ffi_call_VFP (fn, &ecif, cif->bytes, cif->flags, ecif.rvalue);
345 break;
346#endif
347
348 default:
349 FFI_ASSERT(0);
350 break;
351 }
352 if (small_struct)
353 {
354 FFI_ASSERT(rvalue != NULL);
355 memcpy (rvalue, &temp, cif->rtype->size);
356 }
357
358 else if (vfp_struct)
359 {
360 FFI_ASSERT(rvalue != NULL);
361 memcpy (rvalue, ecif.rvalue, cif->rtype->size);
362 }
363
364}
365
368static void ffi_prep_incoming_args_SYSV (char *stack, void **ret,
369 void** args, ffi_cif* cif, float *vfp_stack);
370
371static void ffi_prep_incoming_args_VFP (char *stack, void **ret,
372 void** args, ffi_cif* cif, float *vfp_stack);
373
374void ffi_closure_SYSV (ffi_closure *);
375
376 void ffi_closure_VFP (ffi_closure *);
377
378/* This function is jumped to by the trampoline */
379
380unsigned int FFI_HIDDEN
381ffi_closure_inner (ffi_closure *closure,
382 void **respp, void *args, void *vfp_args)
383{
384 // our various things...
385 ffi_cif *cif;
386 void **arg_area;
387
388 cif = closure->cif;
389 arg_area = (void**) alloca (cif->nargs * sizeof (void*));
390
391 /* this call will initialize ARG_AREA, such that each
392 * element in that array points to the corresponding
393 * value on the stack; and if the function returns
394 * a structure, it will re-set RESP to point to the
395 * structure return address. */
396 if (cif->abi == FFI_VFP)
397 ffi_prep_incoming_args_VFP(args, respp, arg_area, cif, vfp_args);
398 else
399 ffi_prep_incoming_args_SYSV(args, respp, arg_area, cif, vfp_args);
400
401 (closure->fun) (cif, *respp, arg_area, closure->user_data);
402
403 return cif->flags;
404}
405
406/*@-exportheader@*/
407static void
408ffi_prep_incoming_args_SYSV(char *stack, void **rvalue,
409 void **avalue, ffi_cif *cif,
410 /* Used only under VFP hard-float ABI. */
411 float *vfp_stack)
412/*@=exportheader@*/
413{
414 register unsigned int i;
415 register void **p_argv;
416 register char *argp;
417 register ffi_type **p_arg;
418
419 argp = stack;
420
421 if ( cif->flags == FFI_TYPE_STRUCT ) {
422 *rvalue = *(void **) argp;
423 argp += 4;
424 }
425
426 p_argv = avalue;
427
428 for (i = cif->nargs, p_arg = cif->arg_types; (i != 0); i--, p_arg++)
429 {
430 size_t z;
431
432 argp = ffi_align(p_arg, argp);
433
434 z = (*p_arg)->size;
435
436 /* because we're little endian, this is what it turns into. */
437
438 *p_argv = (void*) argp;
439
440 p_argv++;
441 argp += z;
442 }
443
444 return;
445}
446
447/*@-exportheader@*/
448static void
449ffi_prep_incoming_args_VFP(char *stack, void **rvalue,
450 void **avalue, ffi_cif *cif,
451 /* Used only under VFP hard-float ABI. */
452 float *vfp_stack)
453/*@=exportheader@*/
454{
455 register unsigned int i, vi = 0;
456 register void **p_argv;
457 register char *argp, *regp, *eo_regp;
458 register ffi_type **p_arg;
459 char done_with_regs = 0;
460 char stack_used = 0;
461 char is_vfp_type;
462
463 FFI_ASSERT(cif->abi == FFI_VFP);
464 regp = stack;
465 eo_regp = argp = regp + 16;
466
467 if ( cif->flags == FFI_TYPE_STRUCT ) {
468 *rvalue = *(void **) regp;
469 regp += 4;
470 }
471
472 p_argv = avalue;
473
474 for (i = cif->nargs, p_arg = cif->arg_types; (i != 0); i--, p_arg++)
475 {
476 size_t z;
477 is_vfp_type = vfp_type_p (*p_arg);
478
479 if(vi < cif->vfp_nargs && is_vfp_type)
480 {
481 *p_argv++ = (void*)(vfp_stack + cif->vfp_args[vi++]);
482 continue;
483 }
484 else if (!done_with_regs && !is_vfp_type)
485 {
486 char* tregp = ffi_align(p_arg, regp);
487
488 z = (*p_arg)->size;
489 z = (z < 4)? 4 : z; // pad
490
491 /* if the arguments either fits into the registers or uses registers
492 * and stack, while we haven't read other things from the stack */
493 if(tregp + z <= eo_regp || !stack_used)
494 {
495 /* because we're little endian, this is what it turns into. */
496 *p_argv = (void*) tregp;
497
498 p_argv++;
499 regp = tregp + z;
500 // if we read past the last core register, make sure we have not read
501 // from the stack before and continue reading after regp
502 if(regp > eo_regp)
503 {
504 if(stack_used)
505 {
506 abort(); // we should never read past the end of the register
507 // are if the stack is already in use
508 }
509 argp = regp;
510 }
511 if(regp >= eo_regp)
512 {
513 done_with_regs = 1;
514 stack_used = 1;
515 }
516 continue;
517 }
518 }
519 stack_used = 1;
520
521 argp = ffi_align(p_arg, argp);
522
523 z = (*p_arg)->size;
524
525 /* because we're little endian, this is what it turns into. */
526
527 *p_argv = (void*) argp;
528
529 p_argv++;
530 argp += z;
531 }
532
533 return;
534}
535
536/* How to make a trampoline. */
537
538extern unsigned int ffi_arm_trampoline[3];
539
540#if FFI_EXEC_TRAMPOLINE_TABLE
541
542#include <mach/mach.h>
543#include <pthread.h>
544#include <stdio.h>
545#include <stdlib.h>
546
547extern void *ffi_closure_trampoline_table_page;
548
549typedef struct ffi_trampoline_table ffi_trampoline_table;
550typedef struct ffi_trampoline_table_entry ffi_trampoline_table_entry;
551
552struct ffi_trampoline_table {
553 /* contiguous writable and executable pages */
554 vm_address_t config_page;
555 vm_address_t trampoline_page;
556
557 /* free list tracking */
558 uint16_t free_count;
559 ffi_trampoline_table_entry *free_list;
560 ffi_trampoline_table_entry *free_list_pool;
561
562 ffi_trampoline_table *prev;
563 ffi_trampoline_table *next;
564};
565
566struct ffi_trampoline_table_entry {
567 void *(*trampoline)();
568 ffi_trampoline_table_entry *next;
569};
570
571/* Override the standard architecture trampoline size */
572// XXX TODO - Fix
573#undef FFI_TRAMPOLINE_SIZE
574#define FFI_TRAMPOLINE_SIZE 12
575
576/* The trampoline configuration is placed at 4080 bytes prior to the trampoline's entry point */
577#define FFI_TRAMPOLINE_CODELOC_CONFIG(codeloc) ((void **) (((uint8_t *) codeloc) - 4080));
578
579/* The first 16 bytes of the config page are unused, as they are unaddressable from the trampoline page. */
580#define FFI_TRAMPOLINE_CONFIG_PAGE_OFFSET 16
581
582/* Total number of trampolines that fit in one trampoline table */
583#define FFI_TRAMPOLINE_COUNT ((PAGE_SIZE - FFI_TRAMPOLINE_CONFIG_PAGE_OFFSET) / FFI_TRAMPOLINE_SIZE)
584
585static pthread_mutex_t ffi_trampoline_lock = PTHREAD_MUTEX_INITIALIZER;
586static ffi_trampoline_table *ffi_trampoline_tables = NULL;
587
588static ffi_trampoline_table *
589ffi_trampoline_table_alloc ()
590{
591 ffi_trampoline_table *table = NULL;
592
593 /* Loop until we can allocate two contiguous pages */
594 while (table == NULL) {
595 vm_address_t config_page = 0x0;
596 kern_return_t kt;
597
598 /* Try to allocate two pages */
599 kt = vm_allocate (mach_task_self (), &config_page, PAGE_SIZE*2, VM_FLAGS_ANYWHERE);
600 if (kt != KERN_SUCCESS) {
601 fprintf(stderr, "vm_allocate() failure: %d at %s:%d\n", kt, __FILE__, __LINE__);
602 break;
603 }
604
605 /* Now drop the second half of the allocation to make room for the trampoline table */
606 vm_address_t trampoline_page = config_page+PAGE_SIZE;
607 kt = vm_deallocate (mach_task_self (), trampoline_page, PAGE_SIZE);
608 if (kt != KERN_SUCCESS) {
609 fprintf(stderr, "vm_deallocate() failure: %d at %s:%d\n", kt, __FILE__, __LINE__);
610 break;
611 }
612
613 /* Remap the trampoline table to directly follow the config page */
614 vm_prot_t cur_prot;
615 vm_prot_t max_prot;
616
617 kt = vm_remap (mach_task_self (), &trampoline_page, PAGE_SIZE, 0x0, FALSE, mach_task_self (), (vm_address_t) &ffi_closure_trampoline_table_page, FALSE, &cur_prot, &max_prot, VM_INHERIT_SHARE);
618
619 /* If we lost access to the destination trampoline page, drop our config allocation mapping and retry */
620 if (kt != KERN_SUCCESS) {
621 /* Log unexpected failures */
622 if (kt != KERN_NO_SPACE) {
623 fprintf(stderr, "vm_remap() failure: %d at %s:%d\n", kt, __FILE__, __LINE__);
624 }
625
626 vm_deallocate (mach_task_self (), config_page, PAGE_SIZE);
627 continue;
628 }
629
630 /* We have valid trampoline and config pages */
631 table = calloc (1, sizeof(ffi_trampoline_table));
632 table->free_count = FFI_TRAMPOLINE_COUNT;
633 table->config_page = config_page;
634 table->trampoline_page = trampoline_page;
635
636 /* Create and initialize the free list */
637 table->free_list_pool = calloc(FFI_TRAMPOLINE_COUNT, sizeof(ffi_trampoline_table_entry));
638
639 uint16_t i;
640 for (i = 0; i < table->free_count; i++) {
641 ffi_trampoline_table_entry *entry = &table->free_list_pool[i];
642 entry->trampoline = (void *) (table->trampoline_page + (i * FFI_TRAMPOLINE_SIZE));
643
644 if (i < table->free_count - 1)
645 entry->next = &table->free_list_pool[i+1];
646 }
647
648 table->free_list = table->free_list_pool;
649 }
650
651 return table;
652}
653
654void *
655ffi_closure_alloc (size_t size, void **code)
656{
657 /* Create the closure */
658 ffi_closure *closure = malloc(size);
659 if (closure == NULL)
660 return NULL;
661
662 pthread_mutex_lock(&ffi_trampoline_lock);
663
664 /* Check for an active trampoline table with available entries. */
665 ffi_trampoline_table *table = ffi_trampoline_tables;
666 if (table == NULL || table->free_list == NULL) {
667 table = ffi_trampoline_table_alloc ();
668 if (table == NULL) {
669 free(closure);
670 return NULL;
671 }
672
673 /* Insert the new table at the top of the list */
674 table->next = ffi_trampoline_tables;
675 if (table->next != NULL)
676 table->next->prev = table;
677
678 ffi_trampoline_tables = table;
679 }
680
681 /* Claim the free entry */
682 ffi_trampoline_table_entry *entry = ffi_trampoline_tables->free_list;
683 ffi_trampoline_tables->free_list = entry->next;
684 ffi_trampoline_tables->free_count--;
685 entry->next = NULL;
686
687 pthread_mutex_unlock(&ffi_trampoline_lock);
688
689 /* Initialize the return values */
690 *code = entry->trampoline;
691 closure->trampoline_table = table;
692 closure->trampoline_table_entry = entry;
693
694 return closure;
695}
696
697void
698ffi_closure_free (void *ptr)
699{
700 ffi_closure *closure = ptr;
701
702 pthread_mutex_lock(&ffi_trampoline_lock);
703
704 /* Fetch the table and entry references */
705 ffi_trampoline_table *table = closure->trampoline_table;
706 ffi_trampoline_table_entry *entry = closure->trampoline_table_entry;
707
708 /* Return the entry to the free list */
709 entry->next = table->free_list;
710 table->free_list = entry;
711 table->free_count++;
712
713 /* If all trampolines within this table are free, and at least one other table exists, deallocate
714 * the table */
715 if (table->free_count == FFI_TRAMPOLINE_COUNT && ffi_trampoline_tables != table) {
716 /* Remove from the list */
717 if (table->prev != NULL)
718 table->prev->next = table->next;
719
720 if (table->next != NULL)
721 table->next->prev = table->prev;
722
723 /* Deallocate pages */
724 kern_return_t kt;
725 kt = vm_deallocate (mach_task_self (), table->config_page, PAGE_SIZE);
726 if (kt != KERN_SUCCESS)
727 fprintf(stderr, "vm_deallocate() failure: %d at %s:%d\n", kt, __FILE__, __LINE__);
728
729 kt = vm_deallocate (mach_task_self (), table->trampoline_page, PAGE_SIZE);
730 if (kt != KERN_SUCCESS)
731 fprintf(stderr, "vm_deallocate() failure: %d at %s:%d\n", kt, __FILE__, __LINE__);
732
733 /* Deallocate free list */
734 free (table->free_list_pool);
735 free (table);
736 } else if (ffi_trampoline_tables != table) {
737 /* Otherwise, bump this table to the top of the list */
738 table->prev = NULL;
739 table->next = ffi_trampoline_tables;
740 if (ffi_trampoline_tables != NULL)
741 ffi_trampoline_tables->prev = table;
742
743 ffi_trampoline_tables = table;
744 }
745
746 pthread_mutex_unlock (&ffi_trampoline_lock);
747
748 /* Free the closure */
749 free (closure);
750}
751
752#else
753
754#define FFI_INIT_TRAMPOLINE(TRAMP,FUN,CTX) \
755({ unsigned char *__tramp = (unsigned char*)(TRAMP); \
756 unsigned int __fun = (unsigned int)(FUN); \
757 unsigned int __ctx = (unsigned int)(CTX); \
758 unsigned char *insns = (unsigned char *)(CTX); \
759 memcpy (__tramp, ffi_arm_trampoline, sizeof ffi_arm_trampoline); \
760 *(unsigned int*) &__tramp[12] = __ctx; \
761 *(unsigned int*) &__tramp[16] = __fun; \
762 __clear_cache((&__tramp[0]), (&__tramp[19])); /* Clear data mapping. */ \
763 __clear_cache(insns, insns + 3 * sizeof (unsigned int)); \
764 /* Clear instruction \
765 mapping. */ \
766 })
767
768#endif
769
770/* the cif must already be prep'ed */
771
772ffi_status
773 ffi_prep_closure_loc (ffi_closure* closure,
774 ffi_cif* cif,
775 void (*fun)(ffi_cif*,void*,void**,void*),
776 void *user_data,
777 void *codeloc)
778{
779 void (*closure_func)(ffi_closure*) = NULL;
780
781 if (cif->abi == FFI_SYSV)
782 closure_func = &ffi_closure_SYSV;
783#ifdef __ARM_EABI__
784 else if (cif->abi == FFI_VFP)
785 closure_func = &ffi_closure_VFP;
786#endif
787 else
788 return FFI_BAD_ABI;
789
790#if FFI_EXEC_TRAMPOLINE_TABLE
791 void **config = FFI_TRAMPOLINE_CODELOC_CONFIG(codeloc);
792 config[0] = closure;
793 config[1] = closure_func;
794#else
795 FFI_INIT_TRAMPOLINE (&closure->tramp[0], \
796 closure_func, \
797 codeloc);
798#endif
799
800 closure->cif = cif;
801 closure->user_data = user_data;
802 closure->fun = fun;
803
804 return FFI_OK;
805}
806
807/* Below are routines for VFP hard-float support. */
808
809static int rec_vfp_type_p (ffi_type *t, int *elt, int *elnum)
810{
811 switch (t->type)
812 {
813 case FFI_TYPE_FLOAT:
814 case FFI_TYPE_DOUBLE:
815 *elt = (int) t->type;
816 *elnum = 1;
817 return 1;
818
819 case FFI_TYPE_STRUCT_VFP_FLOAT:
820 *elt = FFI_TYPE_FLOAT;
821 *elnum = t->size / sizeof (float);
822 return 1;
823
824 case FFI_TYPE_STRUCT_VFP_DOUBLE:
825 *elt = FFI_TYPE_DOUBLE;
826 *elnum = t->size / sizeof (double);
827 return 1;
828
829 case FFI_TYPE_STRUCT:;
830 {
831 int base_elt = 0, total_elnum = 0;
832 ffi_type **el = t->elements;
833 while (*el)
834 {
835 int el_elt = 0, el_elnum = 0;
836 if (! rec_vfp_type_p (*el, &el_elt, &el_elnum)
837 || (base_elt && base_elt != el_elt)
838 || total_elnum + el_elnum > 4)
839 return 0;
840 base_elt = el_elt;
841 total_elnum += el_elnum;
842 el++;
843 }
844 *elnum = total_elnum;
845 *elt = base_elt;
846 return 1;
847 }
848 default: ;
849 }
850 return 0;
851}
852
853static int vfp_type_p (ffi_type *t)
854{
855 int elt, elnum;
856 if (rec_vfp_type_p (t, &elt, &elnum))
857 {
858 if (t->type == FFI_TYPE_STRUCT)
859 {
860 if (elnum == 1)
861 t->type = elt;
862 else
863 t->type = (elt == FFI_TYPE_FLOAT
864 ? FFI_TYPE_STRUCT_VFP_FLOAT
865 : FFI_TYPE_STRUCT_VFP_DOUBLE);
866 }
867 return (int) t->type;
868 }
869 return 0;
870}
871
872static int place_vfp_arg (ffi_cif *cif, ffi_type *t)
873{
874 short reg = cif->vfp_reg_free;
875 int nregs = t->size / sizeof (float);
876 int align = ((t->type == FFI_TYPE_STRUCT_VFP_FLOAT
877 || t->type == FFI_TYPE_FLOAT) ? 1 : 2);
878 /* Align register number. */
879 if ((reg & 1) && align == 2)
880 reg++;
881 while (reg + nregs <= 16)
882 {
883 int s, new_used = 0;
884 for (s = reg; s < reg + nregs; s++)
885 {
886 new_used |= (1 << s);
887 if (cif->vfp_used & (1 << s))
888 {
889 reg += align;
890 goto next_reg;
891 }
892 }
893 /* Found regs to allocate. */
894 cif->vfp_used |= new_used;
895 cif->vfp_args[cif->vfp_nargs++] = reg;
896
897 /* Update vfp_reg_free. */
898 if (cif->vfp_used & (1 << cif->vfp_reg_free))
899 {
900 reg += nregs;
901 while (cif->vfp_used & (1 << reg))
902 reg += 1;
903 cif->vfp_reg_free = reg;
904 }
905 return 0;
906 next_reg: ;
907 }
908 // done, mark all regs as used
909 cif->vfp_reg_free = 16;
910 cif->vfp_used = 0xFFFF;
911 return 1;
912}
913
914static void layout_vfp_args (ffi_cif *cif)
915{
916 int i;
917 /* Init VFP fields */
918 cif->vfp_used = 0;
919 cif->vfp_nargs = 0;
920 cif->vfp_reg_free = 0;
921 memset (cif->vfp_args, -1, 16); /* Init to -1. */
922
923 for (i = 0; i < cif->nargs; i++)
924 {
925 ffi_type *t = cif->arg_types[i];
926 if (vfp_type_p (t) && place_vfp_arg (cif, t) == 1)
927 {
928 break;
929 }
930 }
931}
ffi_prep_closure_loc
ffi_status ffi_prep_closure_loc(ffi_closure *closure, ffi_cif *cif, void(*fun)(ffi_cif *, void *, void **, void *), void *user_data, void *codeloc)
Definition: ffi.c:928
ffi_prep_cif_machdep
ffi_status ffi_prep_cif_machdep(ffi_cif *cif)
Definition: ffi.c:758
ffi_call
void ffi_call(ffi_cif *cif, void(*fn)(void), void *rvalue, void **avalue)
Definition: ffi.c:813
FFI_INIT_TRAMPOLINE
#define FFI_INIT_TRAMPOLINE(TRAMP, FUN, CTX, FLAGS)
Definition: ffi.c:915
ffi_call_SYSV
void ffi_call_SYSV(unsigned(*)(struct call_context *context, unsigned char *, extended_cif *), struct call_context *context, extended_cif *, size_t, void(*fn)(void))
FFI_TRAMPOLINE_SIZE
#define FFI_TRAMPOLINE_SIZE
Definition: ffitarget.h:45
FFI_SYSV
@ FFI_SYSV
Definition: ffitarget.h:36
ffi_closure_inner
unsigned int FFI_HIDDEN ffi_closure_inner(ffi_closure *closure, void **respp, void *args, void *vfp_args)
Definition: ffi.c:381
ffi_prep_args_VFP
int ffi_prep_args_VFP(char *stack, extended_cif *ecif, float *vfp_space)
Definition: ffi.c:155
ffi_prep_args_SYSV
int ffi_prep_args_SYSV(char *stack, extended_cif *ecif, float *vfp_space)
Definition: ffi.c:128
ffi_call_VFP
void ffi_call_VFP(void(*fn)(void), extended_cif *, unsigned, unsigned, unsigned *)
ffi_closure_VFP
void ffi_closure_VFP(ffi_closure *)
ffi_arm_trampoline
unsigned int ffi_arm_trampoline[3]
FFI_TYPE_STRUCT_VFP_FLOAT
#define FFI_TYPE_STRUCT_VFP_FLOAT
Definition: ffitarget.h:60
FFI_TYPE_STRUCT_VFP_DOUBLE
#define FFI_TYPE_STRUCT_VFP_DOUBLE
Definition: ffitarget.h:61
FFI_VFP
@ FFI_VFP
Definition: ffitarget.h:44
ptr
struct RIMemo * ptr
Definition: debug.c:88
free
#define free(x)
Definition: dln.c:52
ffi_common.h
UINT16
unsigned short UINT16
Definition: ffi_common.h:97
SINT16
signed short SINT16
Definition: ffi_common.h:98
alloca
#define alloca
Definition: ffi_common.h:27
ffi_prep_cif_machdep_var
ffi_status ffi_prep_cif_machdep_var(ffi_cif *cif, unsigned int nfixedargs, unsigned int ntotalargs)
Definition: ffi.c:289
ALIGN
#define ALIGN(v, a)
Definition: ffi_common.h:77
SINT8
signed char SINT8
Definition: ffi_common.h:96
FFI_ASSERT
#define FFI_ASSERT(x)
Definition: ffi_common.h:72
UINT8
unsigned char UINT8
Definition: ffi_common.h:95
UINT32
unsigned int UINT32
Definition: ffi_common.h:99
memcpy
#define memcpy(d, s, n)
Definition: ffi_common.h:55
FFI_HIDDEN
#define FFI_HIDDEN
Definition: fficonfig.h:27
size
voidpf void uLong size
Definition: ioapi.h:138
int
typedef int(ZCALLBACK *close_file_func) OF((voidpf opaque
ffi_closure_SYSV
void ffi_closure_SYSV(void)
Definition: ffi.c:53
FALSE
#define FALSE
Definition: nkf.h:174
NULL
#define NULL
Definition: regenc.h:69
calloc
#define calloc
Definition: st.c:171
malloc
#define malloc
Definition: st.c:170
code
Definition: inftree9.h:24
config_s
Definition: deflate.c:114
extended_cif
Definition: ffi_common.h:87
extended_cif::rvalue
void * rvalue
Definition: ffi_common.h:89
extended_cif::cif
ffi_cif * cif
Definition: ffi_common.h:88
extended_cif::avalue
void ** avalue
Definition: ffi_common.h:90
t
#define t
Definition: symbol.c:253