summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLars Kanis <lars@greiz-reinsdorf.de>2020-12-05 17:51:51 +0100
committerLars Kanis <lars@greiz-reinsdorf.de>2020-12-05 17:51:51 +0100
commit9029cc0da03175c12b412e14f1fdf9814a2cf293 (patch)
tree02c17aa2402afcaa5034e02b18370a47d1fe534c
parentd77419803ef92e9101b189743c9174df9079c60f (diff)
parenta10ac1b8fadeed65064ed9a8e8d5956a9c2d6980 (diff)
downloadffi-9029cc0da03175c12b412e14f1fdf9814a2cf293.tar.gz
Merge branch 'fix-crash-on-apple-silicon' of https://github.com/Watson1978/ffi into Watson1978-fix-crash-on-apple-silicon
-rw-r--r--ext/ffi_c/ClosurePool.c67
-rw-r--r--ext/ffi_c/ClosurePool.h2
-rw-r--r--ext/ffi_c/Function.c2
-rw-r--r--ext/ffi_c/MethodHandle.c2
-rw-r--r--ext/ffi_c/extconf.rb3
5 files changed, 74 insertions, 2 deletions
diff --git a/ext/ffi_c/ClosurePool.c b/ext/ffi_c/ClosurePool.c
index 3934a3b..e15a4ee 100644
--- a/ext/ffi_c/ClosurePool.c
+++ b/ext/ffi_c/ClosurePool.c
@@ -58,6 +58,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))
@@ -107,7 +112,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;
@@ -126,6 +135,8 @@ rbffi_ClosurePool_Free(ClosurePool* pool)
}
}
+#if !USE_FFI_ALLOC
+
Closure*
rbffi_Closure_Alloc(ClosurePool* pool)
{
@@ -161,6 +172,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;
@@ -197,6 +209,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)
{
@@ -232,6 +295,8 @@ getPageSize()
#endif
}
+#if !USE_FFI_ALLOC
+
static void*
allocatePage(void)
{
@@ -264,6 +329,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 28aaaa1..305f8b1 100644
--- a/ext/ffi_c/Function.c
+++ b/ext/ffi_c/Function.c
@@ -844,7 +844,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 c44167e..d047e10 100644
--- a/ext/ffi_c/MethodHandle.c
+++ b/ext/ffi_c/MethodHandle.c
@@ -136,7 +136,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);
diff --git a/ext/ffi_c/extconf.rb b/ext/ffi_c/extconf.rb
index 6dd28aa..a8bdc28 100644
--- a/ext/ffi_c/extconf.rb
+++ b/ext/ffi_c/extconf.rb
@@ -61,6 +61,9 @@ if RUBY_ENGINE == 'ruby' || RUBY_ENGINE == 'rbx'
File.open("Makefile", "a") do |mf|
mf.puts "LIBFFI_HOST=--host=#{RbConfig::CONFIG['host_alias']}" if RbConfig::CONFIG.has_key?("host_alias")
if RbConfig::CONFIG['host_os'].downcase =~ /darwin/
+ if RbConfig::CONFIG['host'] =~ /arm/
+ mf.puts "LIBFFI_HOST=--host=aarch64-apple-#{RbConfig::CONFIG['host_os']}"
+ end
mf.puts "include ${srcdir}/libffi.darwin.mk"
elsif RbConfig::CONFIG['host_os'].downcase =~ /bsd/
mf.puts '.include "${srcdir}/libffi.bsd.mk"'