diff options
author | Watson <watson1978@gmail.com> | 2020-07-13 21:51:57 +0900 |
---|---|---|
committer | Watson <watson1978@gmail.com> | 2020-07-18 13:11:33 +0900 |
commit | 2c9c517876fd115191cd05f62ff8e77ebd493641 (patch) | |
tree | a612f3d1a970f707424c334e20b15492506957d4 /ext/ffi_c | |
parent | d15fa0615df0f20fbcf4b3c23a353a4ec002f555 (diff) | |
download | ffi-2c9c517876fd115191cd05f62ff8e77ebd493641.tar.gz |
Use ffi_closure_alloc() on Apple silicon to fix crash
Diffstat (limited to 'ext/ffi_c')
-rw-r--r-- | ext/ffi_c/ClosurePool.c | 67 | ||||
-rw-r--r-- | ext/ffi_c/ClosurePool.h | 2 | ||||
-rw-r--r-- | ext/ffi_c/Function.c | 2 | ||||
-rw-r--r-- | ext/ffi_c/MethodHandle.c | 2 |
4 files changed, 71 insertions, 2 deletions
diff --git a/ext/ffi_c/ClosurePool.c b/ext/ffi_c/ClosurePool.c index 45411b4..ea660b0 100644 --- a/ext/ffi_c/ClosurePool.c +++ b/ext/ffi_c/ClosurePool.c @@ -66,6 +66,11 @@ #include "ClosurePool.h" +#if (defined(__arm64__) && defined(__APPLE__)) +#define USE_FFI_ALLOC 1 +#else +#define USE_FFI_ALLOC 0 +#endif #ifndef roundup # define roundup(x, y) ((((x)+((y)-1))/(y))*(y)) @@ -115,7 +120,11 @@ cleanup_closure_pool(ClosurePool* pool) for (memory = pool->blocks; memory != NULL; ) { Memory* next = memory->next; +#if !USE_FFI_ALLOC freePage(memory->code); +#else + ffi_closure_free(memory->code); +#endif free(memory->data); free(memory); memory = next; @@ -134,6 +143,8 @@ rbffi_ClosurePool_Free(ClosurePool* pool) } } +#if !USE_FFI_ALLOC + Closure* rbffi_Closure_Alloc(ClosurePool* pool) { @@ -169,6 +180,7 @@ rbffi_Closure_Alloc(ClosurePool* pool) closure->next = &list[i + 1]; closure->pool = pool; closure->code = ((char *)code + (i * trampolineSize)); + closure->pcl = closure->code; if (!(*pool->prep)(pool->ctx, closure->code, closure, errmsg, sizeof(errmsg))) { goto error; @@ -205,6 +217,57 @@ error: return NULL; } +#else + +Closure* +rbffi_Closure_Alloc(ClosurePool* pool) +{ + Closure *closure = NULL; + Memory* block = NULL; + void *code = NULL; + void *pcl = NULL; + char errmsg[256]; + + block = calloc(1, sizeof(*block)); + closure = calloc(1, sizeof(*closure)); + pcl = ffi_closure_alloc(sizeof(ffi_closure), &code); + + if (block == NULL || closure == NULL || pcl == NULL) { + snprintf(errmsg, sizeof(errmsg), "failed to allocate a page. errno=%d (%s)", errno, strerror(errno)); + goto error; + } + + closure->pool = pool; + closure->code = code; + closure->pcl = pcl; + + if (!(*pool->prep)(pool->ctx, closure->code, closure, errmsg, sizeof(errmsg))) { + goto error; + } + + /* Track the allocated page + Closure memory area */ + block->data = closure; + block->code = pcl; + pool->blocks = block; + + /* Thread the new block onto the free list, apart from the first one. */ + pool->refcnt++; + + return closure; + +error: + free(block); + free(closure); + if (pcl != NULL) { + ffi_closure_free(pcl); + } + + rb_raise(rb_eRuntimeError, "%s", errmsg); + return NULL; +} + +#endif /* !USE_FFI_ALLOC */ + void rbffi_Closure_Free(Closure* closure) { @@ -240,6 +303,8 @@ getPageSize() #endif } +#if !USE_FFI_ALLOC + static void* allocatePage(void) { @@ -272,6 +337,8 @@ protectPage(void* page) #endif } +#endif /* !USE_FFI_ALLOC */ + void rbffi_ClosurePool_Init(VALUE module) { diff --git a/ext/ffi_c/ClosurePool.h b/ext/ffi_c/ClosurePool.h index b842375..36619f4 100644 --- a/ext/ffi_c/ClosurePool.h +++ b/ext/ffi_c/ClosurePool.h @@ -36,6 +36,8 @@ struct Closure_ { void* info; /* opaque handle for storing closure-instance specific data */ void* function; /* closure-instance specific function, called by custom trampoline */ void* code; /* The native trampoline code location */ + void* pcl; + struct ClosurePool_* pool; Closure* next; }; diff --git a/ext/ffi_c/Function.c b/ext/ffi_c/Function.c index 506d79b..b1d5a65 100644 --- a/ext/ffi_c/Function.c +++ b/ext/ffi_c/Function.c @@ -849,7 +849,7 @@ callback_prep(void* ctx, void* code, Closure* closure, char* errmsg, size_t errm FunctionType* fnInfo = (FunctionType *) ctx; ffi_status ffiStatus; - ffiStatus = ffi_prep_closure_loc(code, &fnInfo->ffi_cif, callback_invoke, closure, code); + ffiStatus = ffi_prep_closure_loc(closure->pcl, &fnInfo->ffi_cif, callback_invoke, closure, code); if (ffiStatus != FFI_OK) { snprintf(errmsg, errmsgsize, "ffi_prep_closure_loc failed. status=%#x", ffiStatus); return false; diff --git a/ext/ffi_c/MethodHandle.c b/ext/ffi_c/MethodHandle.c index 4dc85fb..bdd5632 100644 --- a/ext/ffi_c/MethodHandle.c +++ b/ext/ffi_c/MethodHandle.c @@ -140,7 +140,7 @@ prep_trampoline(void* ctx, void* code, Closure* closure, char* errmsg, size_t er #if defined(USE_RAW) ffiStatus = ffi_prep_raw_closure(code, &mh_cif, attached_method_invoke, closure); #else - ffiStatus = ffi_prep_closure_loc(code, &mh_cif, attached_method_invoke, closure, code); + ffiStatus = ffi_prep_closure_loc(closure->pcl, &mh_cif, attached_method_invoke, closure, code); #endif if (ffiStatus != FFI_OK) { snprintf(errmsg, errmsgsize, "ffi_prep_closure_loc failed. status=%#x", ffiStatus); |