From: Josh Triplett Date: Sun, 20 Apr 2014 19:03:25 +0000 (-0700) Subject: Support fastcall closures X-Git-Tag: v3.1~8^2 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=d36952273d4fafbda91ecc205fc0824f7cc65e70;p=platform%2Fupstream%2Flibffi.git Support fastcall closures libffi on 32-bit x86 now supports closures for all supported ABIs. Thus, rewrite the last remaining duplicated-by-ABI test (closure_stdcall and closure_thiscall) to use the generic ABI_NUM/ABI_ATTR mechanism. --- diff --git a/src/x86/ffi.c b/src/x86/ffi.c index bcfc153..64b19ec 100644 --- a/src/x86/ffi.c +++ b/src/x86/ffi.c @@ -448,6 +448,8 @@ void FFI_HIDDEN ffi_closure_STDCALL (ffi_closure *) __attribute__ ((regparm(1))); void FFI_HIDDEN ffi_closure_THISCALL (ffi_closure *) __attribute__ ((regparm(1))); +void FFI_HIDDEN ffi_closure_FASTCALL (ffi_closure *) + __attribute__ ((regparm(1))); #else void FFI_HIDDEN ffi_closure_win64 (ffi_closure *); #endif @@ -672,6 +674,12 @@ ffi_prep_closure_loc (ffi_closure* closure, &ffi_closure_SYSV, (void*)codeloc); } + else if (cif->abi == FFI_FASTCALL) + { + FFI_INIT_TRAMPOLINE_STDCALL (&closure->tramp[0], + &ffi_closure_FASTCALL, + (void*)codeloc); + } else if (cif->abi == FFI_THISCALL) { FFI_INIT_TRAMPOLINE_STDCALL (&closure->tramp[0], diff --git a/src/x86/win32.S b/src/x86/win32.S index 0a655c4..699ea46 100644 --- a/src/x86/win32.S +++ b/src/x86/win32.S @@ -472,14 +472,19 @@ cd_epilogue: mov esp, ebp pop ebp pop ecx - mov ecx, DWORD PTR [ecx + (CLOSURE_CIF_OFFSET-10)] - cmp DWORD PTR [ecx + CIF_ABI_OFFSET], 3 - mov ecx, DWORD PTR [ecx + CIF_BYTES_OFFSET] - jne cd_not_thiscall - add ecx, 4 -cd_not_thiscall: pop edx - add esp, ecx + mov ecx, DWORD PTR [ecx + (CLOSURE_CIF_OFFSET-10)] + add esp, DWORD PTR [ecx + CIF_BYTES_OFFSET] + mov ecx, DWORD PTR [ecx + CIF_ABI_OFFSET] + cmp ecx, 3 + je cd_thiscall + cmp ecx, 4 + jne cd_not_fastcall + + add esp, 4 +cd_thiscall: + add esp, 4 +cd_not_fastcall: jmp edx ffi_closure_STDCALL ENDP @@ -679,6 +684,20 @@ USCORE_SYMBOL(ffi_closure_THISCALL): xchg %ecx, (%esp) push %ecx jmp .ffi_closure_STDCALL_internal + + .balign 16 +FFI_HIDDEN(ffi_closure_FASTCALL) + .globl USCORE_SYMBOL(ffi_closure_FASTCALL) +#if defined(X86_WIN32) && !defined(__OS2__) + .def _ffi_closure_FASTCALL; .scl 2; .type 32; .endef +#endif +USCORE_SYMBOL(ffi_closure_FASTCALL): + /* Insert the register arguments on the stack as the first two arguments */ + xchg %edx, 4(%esp) + xchg %ecx, (%esp) + push %edx + push %ecx + jmp .ffi_closure_STDCALL_internal .LFE1: # This assumes we are using gas. @@ -1090,14 +1109,18 @@ USCORE_SYMBOL(ffi_closure_STDCALL): movl %ebp, %esp popl %ebp popl %ecx + popl %edx movl (CLOSURE_CIF_OFFSET-10)(%ecx), %ecx - cmpl $3, CIF_ABI_OFFSET(%ecx) /* FFI_THISCALL */ - movl CIF_BYTES_OFFSET(%ecx), %ecx - jne 1f - addl $4, %ecx -1: popl %edx - addl %ecx, %esp - jmp *%edx + addl CIF_BYTES_OFFSET(%ecx), %esp + movl CIF_ABI_OFFSET(%ecx), %ecx + cmpl $3, %ecx /* FFI_THISCALL */ + je 1f + cmpl $4, %ecx /* FFI_FASTCALL */ + jne 2f + + addl $4, %esp +1: addl $4, %esp +2: jmp *%edx .ffi_closure_STDCALL_end: .LFE5: diff --git a/testsuite/Makefile.am b/testsuite/Makefile.am index acd15c5..da10465 100644 --- a/testsuite/Makefile.am +++ b/testsuite/Makefile.am @@ -35,14 +35,14 @@ libffi.call/cls_align_longdouble_split2.c libffi.call/return_dbl2.c \ libffi.call/return_fl3.c libffi.call/stret_medium.c \ libffi.call/nested_struct6.c libffi.call/closure_fn3.c \ libffi.call/float3.c libffi.call/many2.c \ -libffi.call/closure_stdcall.c libffi.call/cls_align_uint16.c \ +libffi.call/closure_simple.c libffi.call/cls_align_uint16.c \ libffi.call/cls_9byte1.c libffi.call/closure_fn6.c \ libffi.call/cls_double_va.c libffi.call/cls_align_pointer.c \ libffi.call/cls_align_longdouble.c libffi.call/closure_fn2.c \ libffi.call/cls_sshort.c \ libffi.call/nested_struct.c libffi.call/cls_20byte.c \ libffi.call/cls_longdouble.c libffi.call/cls_multi_uchar.c \ -libffi.call/return_uc.c libffi.call/closure_thiscall.c \ +libffi.call/return_uc.c \ libffi.call/cls_18byte.c libffi.call/cls_8byte.c \ libffi.call/promotion.c \ libffi.call/return_dbl.c libffi.call/cls_24byte.c \ diff --git a/testsuite/libffi.call/closure_simple.c b/testsuite/libffi.call/closure_simple.c new file mode 100644 index 0000000..5a4e728 --- /dev/null +++ b/testsuite/libffi.call/closure_simple.c @@ -0,0 +1,55 @@ +/* Area: closure_call + Purpose: Check simple closure handling with all ABIs + Limitations: none. + PR: none. + Originator: */ + +/* { dg-do run } */ +#include "ffitest.h" + +static void +closure_test(ffi_cif* cif __UNUSED__, void* resp, void** args, void* userdata) +{ + *(ffi_arg*)resp = + (int)*(int *)args[0] + (int)(*(int *)args[1]) + + (int)(*(int *)args[2]) + (int)(*(int *)args[3]) + + (int)(intptr_t)userdata; + + printf("%d %d %d %d: %d\n", + (int)*(int *)args[0], (int)(*(int *)args[1]), + (int)(*(int *)args[2]), (int)(*(int *)args[3]), + (int)*(ffi_arg *)resp); + +} + +typedef int (ABI_ATTR *closure_test_type0)(int, int, int, int); + +int main (void) +{ + ffi_cif cif; + void *code; + ffi_closure *pcl = ffi_closure_alloc(sizeof(ffi_closure), &code); + ffi_type * cl_arg_types[17]; + int res; + + cl_arg_types[0] = &ffi_type_uint; + cl_arg_types[1] = &ffi_type_uint; + cl_arg_types[2] = &ffi_type_uint; + cl_arg_types[3] = &ffi_type_uint; + cl_arg_types[4] = NULL; + + /* Initialize the cif */ + CHECK(ffi_prep_cif(&cif, ABI_NUM, 4, + &ffi_type_sint, cl_arg_types) == FFI_OK); + + CHECK(ffi_prep_closure_loc(pcl, &cif, closure_test, + (void *) 3 /* userdata */, code) == FFI_OK); + + res = (*(closure_test_type0)code)(0, 1, 2, 3); + /* { dg-output "0 1 2 3: 9" } */ + + printf("res: %d\n",res); + /* { dg-output "\nres: 9" } */ + + exit(0); +} diff --git a/testsuite/libffi.call/closure_stdcall.c b/testsuite/libffi.call/closure_stdcall.c deleted file mode 100644 index fd1e4b0..0000000 --- a/testsuite/libffi.call/closure_stdcall.c +++ /dev/null @@ -1,56 +0,0 @@ -/* Area: closure_call (stdcall convention) - Purpose: Check handling when caller expects stdcall callee - Limitations: none. - PR: none. - Originator: */ - -/* { dg-do run { target i?86-*-* } } */ -#include "ffitest.h" - -static void -closure_test_stdcall(ffi_cif* cif __UNUSED__, void* resp, void** args, - void* userdata) -{ - *(ffi_arg*)resp = - (int)*(int *)args[0] + (int)(*(int *)args[1]) - + (int)(*(int *)args[2]) + (int)(*(int *)args[3]) - + (int)(intptr_t)userdata; - - printf("%d %d %d %d: %d\n", - (int)*(int *)args[0], (int)(*(int *)args[1]), - (int)(*(int *)args[2]), (int)(*(int *)args[3]), - (int)*(ffi_arg *)resp); - -} - -typedef int (__STDCALL__ *closure_test_type0)(int, int, int, int); - -int main (void) -{ - ffi_cif cif; - void *code; - ffi_closure *pcl = ffi_closure_alloc(sizeof(ffi_closure), &code); - ffi_type * cl_arg_types[17]; - int res; - - cl_arg_types[0] = &ffi_type_uint; - cl_arg_types[1] = &ffi_type_uint; - cl_arg_types[2] = &ffi_type_uint; - cl_arg_types[3] = &ffi_type_uint; - cl_arg_types[4] = NULL; - - /* Initialize the cif */ - CHECK(ffi_prep_cif(&cif, FFI_STDCALL, 4, - &ffi_type_sint, cl_arg_types) == FFI_OK); - - CHECK(ffi_prep_closure_loc(pcl, &cif, closure_test_stdcall, - (void *) 3 /* userdata */, code) == FFI_OK); - - res = (*(closure_test_type0)code)(0, 1, 2, 3); - /* { dg-output "0 1 2 3: 9" } */ - - printf("res: %d\n",res); - /* { dg-output "\nres: 9" } */ - - exit(0); -} diff --git a/testsuite/libffi.call/closure_thiscall.c b/testsuite/libffi.call/closure_thiscall.c deleted file mode 100644 index 8f7d2fa..0000000 --- a/testsuite/libffi.call/closure_thiscall.c +++ /dev/null @@ -1,56 +0,0 @@ -/* Area: closure_call (thiscall convention) - Purpose: Check handling when caller expects thiscall callee - Limitations: none. - PR: none. - Originator: */ - -/* { dg-do run { target i?86-*-* } } */ -#include "ffitest.h" - -static void -closure_test_thiscall(ffi_cif* cif __UNUSED__, void* resp, void** args, - void* userdata) -{ - *(ffi_arg*)resp = - (int)*(int *)args[0] + (int)(*(int *)args[1]) - + (int)(*(int *)args[2]) + (int)(*(int *)args[3]) - + (int)(intptr_t)userdata; - - printf("%d %d %d %d: %d\n", - (int)*(int *)args[0], (int)(*(int *)args[1]), - (int)(*(int *)args[2]), (int)(*(int *)args[3]), - (int)*(ffi_arg *)resp); - -} - -typedef int (__THISCALL__ *closure_test_type0)(int, int, int, int); - -int main (void) -{ - ffi_cif cif; - void *code; - ffi_closure *pcl = ffi_closure_alloc(sizeof(ffi_closure), &code); - ffi_type * cl_arg_types[17]; - int res; - - cl_arg_types[0] = &ffi_type_uint; - cl_arg_types[1] = &ffi_type_uint; - cl_arg_types[2] = &ffi_type_uint; - cl_arg_types[3] = &ffi_type_uint; - cl_arg_types[4] = NULL; - - /* Initialize the cif */ - CHECK(ffi_prep_cif(&cif, FFI_THISCALL, 4, - &ffi_type_sint, cl_arg_types) == FFI_OK); - - CHECK(ffi_prep_closure_loc(pcl, &cif, closure_test_thiscall, - (void *) 3 /* userdata */, code) == FFI_OK); - - res = (*(closure_test_type0)code)(0, 1, 2, 3); - /* { dg-output "0 1 2 3: 9" } */ - - printf("res: %d\n",res); - /* { dg-output "\nres: 9" } */ - - exit(0); -}