ยปCore Development>Code coverage>Modules/_ctypes/libffi/src/arm/ffi.c

Python code coverage for Modules/_ctypes/libffi/src/arm/ffi.c

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