9a567ff5d0
* Updated for Python 3.7.1
245 lines
7.3 KiB
C
245 lines
7.3 KiB
C
/* -----------------------------------------------------------------------
|
|
prep_cif.c - Copyright (c) 2011, 2012 Anthony Green
|
|
Copyright (c) 1996, 1998, 2007 Red Hat, Inc.
|
|
|
|
Permission is hereby granted, free of charge, to any person obtaining
|
|
a copy of this software and associated documentation files (the
|
|
``Software''), to deal in the Software without restriction, including
|
|
without limitation the rights to use, copy, modify, merge, publish,
|
|
distribute, sublicense, and/or sell copies of the Software, and to
|
|
permit persons to whom the Software is furnished to do so, subject to
|
|
the following conditions:
|
|
|
|
The above copyright notice and this permission notice shall be included
|
|
in all copies or substantial portions of the Software.
|
|
|
|
THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND,
|
|
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
|
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
|
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
|
DEALINGS IN THE SOFTWARE.
|
|
----------------------------------------------------------------------- */
|
|
|
|
#include <ffi.h>
|
|
#include <ffi_common.h>
|
|
#include <stdlib.h>
|
|
|
|
/* Round up to FFI_SIZEOF_ARG. */
|
|
|
|
#define STACK_ARG_SIZE(x) ALIGN(x, FFI_SIZEOF_ARG)
|
|
|
|
/* Perform machine independent initialization of aggregate type
|
|
specifications. */
|
|
|
|
static ffi_status initialize_aggregate(ffi_type *arg)
|
|
{
|
|
ffi_type **ptr;
|
|
|
|
if (UNLIKELY(arg == NULL || arg->elements == NULL))
|
|
return FFI_BAD_TYPEDEF;
|
|
|
|
arg->size = 0;
|
|
arg->alignment = 0;
|
|
|
|
ptr = &(arg->elements[0]);
|
|
|
|
if (UNLIKELY(ptr == 0))
|
|
return FFI_BAD_TYPEDEF;
|
|
|
|
while ((*ptr) != NULL)
|
|
{
|
|
if (UNLIKELY(((*ptr)->size == 0)
|
|
&& (initialize_aggregate((*ptr)) != FFI_OK)))
|
|
return FFI_BAD_TYPEDEF;
|
|
|
|
/* Perform a sanity check on the argument type */
|
|
FFI_ASSERT_VALID_TYPE(*ptr);
|
|
|
|
arg->size = ALIGN(arg->size, (*ptr)->alignment);
|
|
arg->size += (*ptr)->size;
|
|
|
|
arg->alignment = (arg->alignment > (*ptr)->alignment) ?
|
|
arg->alignment : (*ptr)->alignment;
|
|
|
|
ptr++;
|
|
}
|
|
|
|
/* Structure size includes tail padding. This is important for
|
|
structures that fit in one register on ABIs like the PowerPC64
|
|
Linux ABI that right justify small structs in a register.
|
|
It's also needed for nested structure layout, for example
|
|
struct A { long a; char b; }; struct B { struct A x; char y; };
|
|
should find y at an offset of 2*sizeof(long) and result in a
|
|
total size of 3*sizeof(long). */
|
|
arg->size = ALIGN (arg->size, arg->alignment);
|
|
|
|
/* On some targets, the ABI defines that structures have an additional
|
|
alignment beyond the "natural" one based on their elements. */
|
|
#ifdef FFI_AGGREGATE_ALIGNMENT
|
|
if (FFI_AGGREGATE_ALIGNMENT > arg->alignment)
|
|
arg->alignment = FFI_AGGREGATE_ALIGNMENT;
|
|
#endif
|
|
|
|
if (arg->size == 0)
|
|
return FFI_BAD_TYPEDEF;
|
|
else
|
|
return FFI_OK;
|
|
}
|
|
|
|
#ifndef __CRIS__
|
|
/* The CRIS ABI specifies structure elements to have byte
|
|
alignment only, so it completely overrides this functions,
|
|
which assumes "natural" alignment and padding. */
|
|
|
|
/* Perform machine independent ffi_cif preparation, then call
|
|
machine dependent routine. */
|
|
|
|
/* For non variadic functions isvariadic should be 0 and
|
|
nfixedargs==ntotalargs.
|
|
|
|
For variadic calls, isvariadic should be 1 and nfixedargs
|
|
and ntotalargs set as appropriate. nfixedargs must always be >=1 */
|
|
|
|
|
|
ffi_status FFI_HIDDEN ffi_prep_cif_core(ffi_cif *cif, ffi_abi abi,
|
|
unsigned int isvariadic,
|
|
unsigned int nfixedargs,
|
|
unsigned int ntotalargs,
|
|
ffi_type *rtype, ffi_type **atypes)
|
|
{
|
|
unsigned bytes = 0;
|
|
unsigned int i;
|
|
ffi_type **ptr;
|
|
|
|
FFI_ASSERT(cif != NULL);
|
|
FFI_ASSERT((!isvariadic) || (nfixedargs >= 1));
|
|
FFI_ASSERT(nfixedargs <= ntotalargs);
|
|
|
|
if (! (abi > FFI_FIRST_ABI && abi < FFI_LAST_ABI))
|
|
return FFI_BAD_ABI;
|
|
|
|
cif->abi = abi;
|
|
cif->arg_types = atypes;
|
|
cif->nargs = ntotalargs;
|
|
cif->rtype = rtype;
|
|
|
|
cif->flags = 0;
|
|
|
|
#if HAVE_LONG_DOUBLE_VARIANT
|
|
ffi_prep_types (abi);
|
|
#endif
|
|
|
|
/* Initialize the return type if necessary */
|
|
if ((cif->rtype->size == 0) && (initialize_aggregate(cif->rtype) != FFI_OK))
|
|
return FFI_BAD_TYPEDEF;
|
|
|
|
/* Perform a sanity check on the return type */
|
|
FFI_ASSERT_VALID_TYPE(cif->rtype);
|
|
|
|
/* x86, x86-64 and s390 stack space allocation is handled in prep_machdep. */
|
|
#if !defined M68K && !defined X86_ANY && !defined S390 && !defined PA
|
|
/* Make space for the return structure pointer */
|
|
if (cif->rtype->type == FFI_TYPE_STRUCT
|
|
#ifdef SPARC
|
|
&& (cif->abi != FFI_V9 || cif->rtype->size > 32)
|
|
#endif
|
|
#ifdef TILE
|
|
&& (cif->rtype->size > 10 * FFI_SIZEOF_ARG)
|
|
#endif
|
|
#ifdef XTENSA
|
|
&& (cif->rtype->size > 16)
|
|
#endif
|
|
#ifdef NIOS2
|
|
&& (cif->rtype->size > 8)
|
|
#endif
|
|
)
|
|
bytes = STACK_ARG_SIZE(sizeof(void*));
|
|
#endif
|
|
|
|
for (ptr = cif->arg_types, i = cif->nargs; i > 0; i--, ptr++)
|
|
{
|
|
|
|
/* Initialize any uninitialized aggregate type definitions */
|
|
if (((*ptr)->size == 0) && (initialize_aggregate((*ptr)) != FFI_OK))
|
|
return FFI_BAD_TYPEDEF;
|
|
|
|
/* Perform a sanity check on the argument type, do this
|
|
check after the initialization. */
|
|
FFI_ASSERT_VALID_TYPE(*ptr);
|
|
|
|
#if !defined X86_ANY && !defined S390 && !defined PA
|
|
#ifdef SPARC
|
|
if (((*ptr)->type == FFI_TYPE_STRUCT
|
|
&& ((*ptr)->size > 16 || cif->abi != FFI_V9))
|
|
|| ((*ptr)->type == FFI_TYPE_LONGDOUBLE
|
|
&& cif->abi != FFI_V9))
|
|
bytes += sizeof(void*);
|
|
else
|
|
#endif
|
|
{
|
|
/* Add any padding if necessary */
|
|
if (((*ptr)->alignment - 1) & bytes)
|
|
bytes = (unsigned)ALIGN(bytes, (*ptr)->alignment);
|
|
|
|
#ifdef TILE
|
|
if (bytes < 10 * FFI_SIZEOF_ARG &&
|
|
bytes + STACK_ARG_SIZE((*ptr)->size) > 10 * FFI_SIZEOF_ARG)
|
|
{
|
|
/* An argument is never split between the 10 parameter
|
|
registers and the stack. */
|
|
bytes = 10 * FFI_SIZEOF_ARG;
|
|
}
|
|
#endif
|
|
#ifdef XTENSA
|
|
if (bytes <= 6*4 && bytes + STACK_ARG_SIZE((*ptr)->size) > 6*4)
|
|
bytes = 6*4;
|
|
#endif
|
|
|
|
bytes += STACK_ARG_SIZE((*ptr)->size);
|
|
}
|
|
#endif
|
|
}
|
|
|
|
cif->bytes = bytes;
|
|
|
|
/* Perform machine dependent cif processing */
|
|
#ifdef FFI_TARGET_SPECIFIC_VARIADIC
|
|
if (isvariadic)
|
|
return ffi_prep_cif_machdep_var(cif, nfixedargs, ntotalargs);
|
|
#endif
|
|
|
|
return ffi_prep_cif_machdep(cif);
|
|
}
|
|
#endif /* not __CRIS__ */
|
|
|
|
ffi_status ffi_prep_cif(ffi_cif *cif, ffi_abi abi, unsigned int nargs,
|
|
ffi_type *rtype, ffi_type **atypes)
|
|
{
|
|
return ffi_prep_cif_core(cif, abi, 0, nargs, nargs, rtype, atypes);
|
|
}
|
|
|
|
ffi_status ffi_prep_cif_var(ffi_cif *cif,
|
|
ffi_abi abi,
|
|
unsigned int nfixedargs,
|
|
unsigned int ntotalargs,
|
|
ffi_type *rtype,
|
|
ffi_type **atypes)
|
|
{
|
|
return ffi_prep_cif_core(cif, abi, 1, nfixedargs, ntotalargs, rtype, atypes);
|
|
}
|
|
|
|
#if FFI_CLOSURES
|
|
|
|
ffi_status
|
|
ffi_prep_closure (ffi_closure* closure,
|
|
ffi_cif* cif,
|
|
void (*fun)(ffi_cif*,void*,void**,void*),
|
|
void *user_data)
|
|
{
|
|
return ffi_prep_closure_loc (closure, cif, fun, user_data, closure);
|
|
}
|
|
|
|
#endif
|