Sync the darwin/x86 port libffi with the copy in PyObjC. This fixes a number

of bugs in that port. The most annoying ones were due to some subtle differences
between the document ABI and the actual implementation :-(

(there are no python unittests that fail without this patch, but without it
 some of libffi's unittests fail).
This commit is contained in:
Ronald Oussoren 2006-07-04 12:30:22 +00:00
parent 74c3ea0a0f
commit b4a6a566ff
2 changed files with 134 additions and 102 deletions

View file

@ -35,6 +35,13 @@
#include <fficonfig.h>
#include <ffi.h>
#ifdef PyObjC_STRICT_DEBUGGING
/* XXX: Debugging of stack alignment, to be removed */
#define ASSERT_STACK_ALIGNED movdqa -16(%esp), %xmm0
#else
#define ASSERT_STACK_ALIGNED
#endif
.text
.globl _ffi_prep_args
@ -47,30 +54,41 @@ _ffi_call_SYSV:
pushl %ebp
.LCFI0:
movl %esp,%ebp
subl $8,%esp
ASSERT_STACK_ALIGNED
.LCFI1:
/* Make room for all of the new args. */
movl 16(%ebp),%ecx
subl %ecx,%esp
ASSERT_STACK_ALIGNED
movl %esp,%eax
/* Place all of the ffi_prep_args in position */
subl $8,%esp
pushl 12(%ebp)
pushl %eax
call *8(%ebp)
ASSERT_STACK_ALIGNED
/* Return stack to previous state and call the function */
addl $8,%esp
addl $16,%esp
ASSERT_STACK_ALIGNED
call *28(%ebp)
/* Remove the space we pushed for the args */
/* XXX: return returns return with 'ret $4', that upsets the stack! */
movl 16(%ebp),%ecx
addl %ecx,%esp
/* Load %ecx with the return type code */
movl 20(%ebp),%ecx
/* If the return value pointer is NULL, assume no return value. */
cmpl $0,24(%ebp)
jne retint
@ -117,17 +135,47 @@ retlongdouble:
retint64:
cmpl $FFI_TYPE_SINT64,%ecx
jne retstruct
jne retstruct1b
/* Load %ecx with the pointer to storage for the return value */
movl 24(%ebp),%ecx
movl %eax,0(%ecx)
movl %edx,4(%ecx)
jmp epilogue
retstruct1b:
cmpl $FFI_TYPE_SINT8,%ecx
jne retstruct2b
movl 24(%ebp),%ecx
movb %al,0(%ecx)
jmp epilogue
retstruct2b:
cmpl $FFI_TYPE_SINT16,%ecx
jne retstruct
movl 24(%ebp),%ecx
movw %ax,0(%ecx)
jmp epilogue
retstruct:
cmpl $FFI_TYPE_STRUCT,%ecx
jne noretval
/* Nothing to do! */
subl $4,%esp
ASSERT_STACK_ALIGNED
addl $8,%esp
movl %ebp, %esp
popl %ebp
ret
noretval:
epilogue:
ASSERT_STACK_ALIGNED
addl $8, %esp
movl %ebp,%esp
popl %ebp
ret

View file

@ -140,7 +140,7 @@ ffi_status ffi_prep_cif_machdep(ffi_cif *cif)
switch (cif->rtype->type)
{
case FFI_TYPE_VOID:
#if !defined(X86_WIN32)
#if !defined(X86_WIN32) && !defined(X86_DARWIN)
case FFI_TYPE_STRUCT:
#endif
case FFI_TYPE_SINT64:
@ -154,7 +154,7 @@ ffi_status ffi_prep_cif_machdep(ffi_cif *cif)
cif->flags = FFI_TYPE_SINT64;
break;
#if defined X86_WIN32
#if defined(X86_WIN32) || defined(X86_DARWIN)
case FFI_TYPE_STRUCT:
if (cif->rtype->size == 1)
@ -186,10 +186,11 @@ ffi_status ffi_prep_cif_machdep(ffi_cif *cif)
}
/* Darwin: The stack needs to be aligned to a multiple of 16 bytes */
#if 0
#if 1
cif->bytes = (cif->bytes + 15) & ~0xF;
#endif
return FFI_OK;
}
@ -221,7 +222,6 @@ void ffi_call(/*@dependent@*/ ffi_cif *cif,
/*@dependent@*/ void **avalue)
{
extended_cif ecif;
int flags;
ecif.cif = cif;
ecif.avalue = avalue;
@ -238,20 +238,6 @@ void ffi_call(/*@dependent@*/ ffi_cif *cif,
else
ecif.rvalue = rvalue;
flags = cif->flags;
if (flags == FFI_TYPE_STRUCT) {
if (cif->rtype->size == 8) {
flags = FFI_TYPE_SINT64;
} else if (cif->rtype->size == 4) {
flags = FFI_TYPE_INT;
} else if (cif->rtype->size == 2) {
flags = FFI_TYPE_INT;
} else if (cif->rtype->size == 1) {
flags = FFI_TYPE_INT;
}
}
switch (cif->abi)
{
case FFI_SYSV:
@ -260,8 +246,8 @@ void ffi_call(/*@dependent@*/ ffi_cif *cif,
* block is a multiple of 16. Then add 8 to compensate for local variables
* in ffi_call_SYSV.
*/
ffi_call_SYSV(ffi_prep_args, &ecif, ALIGN(cif->bytes, 16) +8,
flags, ecif.rvalue, fn);
ffi_call_SYSV(ffi_prep_args, &ecif, cif->bytes,
cif->flags, ecif.rvalue, fn);
/*@=usedef@*/
break;
#ifdef X86_WIN32
@ -281,8 +267,6 @@ void ffi_call(/*@dependent@*/ ffi_cif *cif,
/** private members **/
static void ffi_prep_incoming_args_SYSV (char *stack, void **ret,
void** args, ffi_cif* cif);
static void ffi_closure_SYSV (ffi_closure *)
__attribute__ ((regparm(1)));
#if !FFI_NO_RAW_API
@ -290,83 +274,8 @@ static void ffi_closure_raw_SYSV (ffi_raw_closure *)
__attribute__ ((regparm(1)));
#endif
/* This function is jumped to by the trampoline */
static void
ffi_closure_SYSV (closure)
ffi_closure *closure;
{
// this is our return value storage
long double res;
// our various things...
ffi_cif *cif;
void **arg_area;
unsigned short rtype;
void *resp = (void*)&res;
void *args = __builtin_dwarf_cfa ();
cif = closure->cif;
arg_area = (void**) alloca (cif->nargs * sizeof (void*));
/* this call will initialize ARG_AREA, such that each
* element in that array points to the corresponding
* value on the stack; and if the function returns
* a structure, it will re-set RESP to point to the
* structure return address. */
ffi_prep_incoming_args_SYSV(args, (void**)&resp, arg_area, cif);
(closure->fun) (cif, resp, arg_area, closure->user_data);
rtype = cif->flags;
if (!retval_on_stack(cif->rtype) && cif->flags == FFI_TYPE_STRUCT) {
if (cif->rtype->size == 8) {
rtype = FFI_TYPE_SINT64;
} else {
rtype = FFI_TYPE_INT;
}
}
/* now, do a generic return based on the value of rtype */
if (rtype == FFI_TYPE_INT)
{
asm ("movl (%0),%%eax" : : "r" (resp) : "eax");
}
else if (rtype == FFI_TYPE_FLOAT)
{
asm ("flds (%0)" : : "r" (resp) : "st" );
}
else if (rtype == FFI_TYPE_DOUBLE)
{
asm ("fldl (%0)" : : "r" (resp) : "st", "st(1)" );
}
else if (rtype == FFI_TYPE_LONGDOUBLE)
{
asm ("fldt (%0)" : : "r" (resp) : "st", "st(1)" );
}
else if (rtype == FFI_TYPE_SINT64)
{
asm ("movl 0(%0),%%eax;"
"movl 4(%0),%%edx"
: : "r"(resp)
: "eax", "edx");
}
#ifdef X86_WIN32
else if (rtype == FFI_TYPE_SINT8) /* 1-byte struct */
{
asm ("movsbl (%0),%%eax" : : "r" (resp) : "eax");
}
else if (rtype == FFI_TYPE_SINT16) /* 2-bytes struct */
{
asm ("movswl (%0),%%eax" : : "r" (resp) : "eax");
}
#endif
}
/*@-exportheader@*/
static void
static inline void
ffi_prep_incoming_args_SYSV(char *stack, void **rvalue,
void **avalue, ffi_cif *cif)
/*@=exportheader@*/
@ -407,6 +316,81 @@ ffi_prep_incoming_args_SYSV(char *stack, void **rvalue,
return;
}
/* This function is jumped to by the trampoline */
static void
ffi_closure_SYSV (closure)
ffi_closure *closure;
{
// this is our return value storage
long double res;
// our various things...
ffi_cif *cif;
void **arg_area;
void *resp = (void*)&res;
void *args = __builtin_dwarf_cfa ();
cif = closure->cif;
arg_area = (void**) alloca (cif->nargs * sizeof (void*));
/* this call will initialize ARG_AREA, such that each
* element in that array points to the corresponding
* value on the stack; and if the function returns
* a structure, it will re-set RESP to point to the
* structure return address. */
ffi_prep_incoming_args_SYSV(args, (void**)&resp, arg_area, cif);
(closure->fun) (cif, resp, arg_area, closure->user_data);
/* now, do a generic return based on the value of rtype */
if (cif->flags == FFI_TYPE_INT)
{
asm ("movl (%0),%%eax" : : "r" (resp) : "eax");
}
else if (cif->flags == FFI_TYPE_FLOAT)
{
asm ("flds (%0)" : : "r" (resp) : "st" );
}
else if (cif->flags == FFI_TYPE_DOUBLE)
{
asm ("fldl (%0)" : : "r" (resp) : "st", "st(1)" );
}
else if (cif->flags == FFI_TYPE_LONGDOUBLE)
{
asm ("fldt (%0)" : : "r" (resp) : "st", "st(1)" );
}
else if (cif->flags == FFI_TYPE_SINT64)
{
asm ("movl 0(%0),%%eax;"
"movl 4(%0),%%edx"
: : "r"(resp)
: "eax", "edx");
}
#if defined(X86_WIN32) || defined(X86_DARWIN)
else if (cif->flags == FFI_TYPE_SINT8) /* 1-byte struct */
{
asm ("movsbl (%0),%%eax" : : "r" (resp) : "eax");
}
else if (cif->flags == FFI_TYPE_SINT16) /* 2-bytes struct */
{
asm ("movswl (%0),%%eax" : : "r" (resp) : "eax");
}
#endif
else if (cif->flags == FFI_TYPE_STRUCT)
{
asm ("lea -8(%ebp),%esp;"
"pop %esi;"
"pop %edi;"
"pop %ebp;"
"ret $4");
}
}
/* How to make a trampoline. Derived from gcc/config/i386/i386.c. */
#define FFI_INIT_TRAMPOLINE(TRAMP,FUN,CTX) \