From 72d863eb35cb12b4b8e8e29479f728d50f603ed0 Mon Sep 17 00:00:00 2001
From: Rich Megginson <rmeggins@redhat.com>
Date: Wed, 12 Sep 2018 15:45:59 -0600
Subject: [PATCH] Revert "Revert "Do closures via libffi""

This reverts commit 94441aa5f8b694b62f70528011b32c5db3d42dd4.

(cherry picked from commit b26df881ee2c2f003f1ad1311f5c207a5a47978f)
---
 ext/ffi_c/Call.c                       |  23 +-
 ext/ffi_c/Call.h                       |   9 -
 ext/ffi_c/Closure.c                    |  54 +++++
 ext/ffi_c/{ClosurePool.h => Closure.h} |  36 ++-
 ext/ffi_c/ClosurePool.c                | 283 -----------------------
 ext/ffi_c/Function.c                   |  41 ++--
 ext/ffi_c/Function.h                   |   3 +-
 ext/ffi_c/FunctionInfo.c               |   4 -
 ext/ffi_c/MethodHandle.c               | 301 +++----------------------
 ext/ffi_c/ffi.c                        |   4 +-
 10 files changed, 120 insertions(+), 638 deletions(-)
 create mode 100644 ext/ffi_c/Closure.c
 rename ext/ffi_c/{ClosurePool.h => Closure.h} (64%)
 delete mode 100644 ext/ffi_c/ClosurePool.c

diff --git a/ext/ffi_c/Call.c b/ext/ffi_c/Call.c
index 3a7c690..7fa7470 100644
--- a/ext/ffi_c/Call.c
+++ b/ext/ffi_c/Call.c
@@ -63,28 +63,7 @@
 #include "Thread.h"
 #include "LongDouble.h"
 
-#ifdef USE_RAW
-#  ifndef __i386__
-#    error "RAW argument packing only supported on i386"
-#  endif
-
-#define INT8_ADJ (4)
-#define INT16_ADJ (4)
-#define INT32_ADJ (4)
-#define INT64_ADJ (8)
-#define LONG_ADJ (sizeof(long))
-#define FLOAT32_ADJ (4)
-#define FLOAT64_ADJ (8)
-#define ADDRESS_ADJ (sizeof(void *))
-#define LONGDOUBLE_ADJ (ffi_type_longdouble.alignment)
-
-#endif /* USE_RAW */
-
-#ifdef USE_RAW
-#  define ADJ(p, a) ((p) = (FFIStorage*) (((char *) p) + a##_ADJ))
-#else
-#  define ADJ(p, a) (++(p))
-#endif
+#define ADJ(p, a) (++(p))
 
 static void* callback_param(VALUE proc, VALUE cbinfo);
 static inline void* getPointer(VALUE value, int type);
diff --git a/ext/ffi_c/Call.h b/ext/ffi_c/Call.h
index d9b9eda..d61c010 100644
--- a/ext/ffi_c/Call.h
+++ b/ext/ffi_c/Call.h
@@ -39,15 +39,6 @@
 extern "C" {
 #endif
 
-#if defined(__i386__) && \
-  (defined(HAVE_RAW_API) || defined(USE_INTERNAL_LIBFFI)) && \
-  !defined(_WIN32) && !defined(__WIN32__)
-#  define USE_RAW
-#endif
-
-#if (defined(__i386__) || defined(__x86_64__)) && !(defined(_WIN32) || defined(__WIN32__))
-#  define BYPASS_FFI 1
-#endif
 
 typedef union {
 #ifdef USE_RAW
diff --git a/ext/ffi_c/Closure.c b/ext/ffi_c/Closure.c
new file mode 100644
index 0000000..844c74e
--- /dev/null
+++ b/ext/ffi_c/Closure.c
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 2009, 2010 Wayne Meissner
+ * Copyright (c) 2008-2016, Ruby FFI project contributors
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in the
+ *       documentation and/or other materials provided with the distribution.
+ *     * Neither the name of the Ruby FFI project nor the
+ *       names of its contributors may be used to endorse or promote products
+ *       derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <ffi.h>
+#include "Closure.h"
+#include "rbffi.h"
+
+Closure* rbffi_Closure_Alloc(void)
+{
+    Closure *self;
+
+    self = xmalloc(sizeof(Closure));
+    self->libffi_closure = ffi_closure_alloc(sizeof(ffi_closure), &self->libffi_trampoline);
+    if (!self->libffi_closure) {
+        return NULL;
+    }
+
+    return self;
+}
+
+void rbffi_Closure_Free(Closure *self)
+{
+    ffi_closure_free(self->libffi_closure);
+    free(self);
+}
+
+void rbffi_Closure_Init(VALUE moduleFFI)
+{
+}
diff --git a/ext/ffi_c/ClosurePool.h b/ext/ffi_c/Closure.h
similarity index 64%
rename from ext/ffi_c/ClosurePool.h
rename to ext/ffi_c/Closure.h
index b842375..a292da9 100644
--- a/ext/ffi_c/ClosurePool.h
+++ b/ext/ffi_c/Closure.h
@@ -1,6 +1,6 @@
 /*
  * Copyright (c) 2009, 2010 Wayne Meissner
- * Copyright (c) 2008-2013, Ruby FFI project contributors
+ * Copyright (c) 2008-2016, Ruby FFI project contributors
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -26,32 +26,22 @@
  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
-#ifndef RUBYFFI_CLOSUREPOOL_H
-#define RUBYFFI_CLOSUREPOOL_H
+#ifndef RUBYFFI_CLOSURE_H
+#define RUBYFFI_CLOSURE_H
 
-typedef struct ClosurePool_ ClosurePool;
-typedef struct Closure_ Closure;
+#include <ruby.h>
 
-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 */
-    struct ClosurePool_* pool;
-    Closure* next;
-};
+typedef struct Closure_ {
+    void* info;              /* Data to pass when calling */
+    void* function;          /* Function to call */
+    void* libffi_trampoline; /* Calls .function */
+    void *libffi_closure;    /* Allocates .libffi_trampoline */
+} Closure;
 
-void rbffi_ClosurePool_Init(VALUE module);
-
-ClosurePool* rbffi_ClosurePool_New(int closureSize, 
-        bool (*prep)(void* ctx, void *code, Closure* closure, char* errbuf, size_t errbufsize),
-        void* ctx);
-
-void rbffi_ClosurePool_Free(ClosurePool *);
-
-Closure* rbffi_Closure_Alloc(ClosurePool *);
+Closure* rbffi_Closure_Alloc();
 void rbffi_Closure_Free(Closure *);
 
-void* rbffi_Closure_GetCodeAddress(Closure *);
+void rbffi_Closure_Init(VALUE ffiModule);
 
-#endif /* RUBYFFI_CLOSUREPOOL_H */
+#endif /* RUBYFFI_CLOSURE_H */
 
diff --git a/ext/ffi_c/ClosurePool.c b/ext/ffi_c/ClosurePool.c
deleted file mode 100644
index 5499b40..0000000
--- a/ext/ffi_c/ClosurePool.c
+++ /dev/null
@@ -1,283 +0,0 @@
-/*
- * Copyright (c) 2009, 2010 Wayne Meissner
- * Copyright (c) 2008-2013, Ruby FFI project contributors
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *     * Redistributions of source code must retain the above copyright
- *       notice, this list of conditions and the following disclaimer.
- *     * Redistributions in binary form must reproduce the above copyright
- *       notice, this list of conditions and the following disclaimer in the
- *       documentation and/or other materials provided with the distribution.
- *     * Neither the name of the Ruby FFI project nor the
- *       names of its contributors may be used to endorse or promote products
- *       derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
- * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
- * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
- * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#ifndef _MSC_VER
-#include <sys/param.h>
-#endif
-#include <sys/types.h>
-#if defined(__CYGWIN__) || !defined(_WIN32)
-#  include <sys/mman.h>
-#endif
-#include <stdio.h>
-#ifndef _MSC_VER
-# include <stdint.h>
-# include <stdbool.h>
-#else
-# include "win32/stdbool.h"
-# include "win32/stdint.h"
-#endif
-#if defined(__CYGWIN__) || !defined(_WIN32)
-#  include <unistd.h>
-#else
-#  include <winsock2.h>
-#  define _WINSOCKAPI_
-#  include <windows.h>
-#endif
-#include <errno.h>
-#include <ruby.h>
-
-#if defined(_MSC_VER) && !defined(INT8_MIN)
-#  include "win32/stdint.h"
-#endif
-#include <ffi.h>
-#include "rbffi.h"
-#include "compat.h"
-
-#include "Function.h"
-#include "Types.h"
-#include "Type.h"
-#include "LastError.h"
-#include "Call.h"
-
-#include "ClosurePool.h"
-
-
-#ifndef roundup
-#  define roundup(x, y)   ((((x)+((y)-1))/(y))*(y))
-#endif
-#ifdef _WIN32
-  typedef char* caddr_t;
-#endif
-
-typedef struct Memory {
-    void* code;
-    void* data;
-    struct Memory* next;
-} Memory;
-
-struct ClosurePool_ {
-    void* ctx;
-    int closureSize;
-    bool (*prep)(void* ctx, void *code, Closure* closure, char* errbuf, size_t errbufsize);
-    struct Memory* blocks; /* Keeps track of all the allocated memory for this pool */
-    Closure* list;
-    long refcnt;
-};
-
-static long pageSize;
-
-static void* allocatePage(void);
-static bool freePage(void *);
-static bool protectPage(void *);
-
-ClosurePool*
-rbffi_ClosurePool_New(int closureSize, 
-        bool (*prep)(void* ctx, void *code, Closure* closure, char* errbuf, size_t errbufsize),
-        void* ctx)
-{
-    ClosurePool* pool;
-
-    pool = xcalloc(1, sizeof(*pool));
-    pool->closureSize = closureSize;
-    pool->ctx = ctx;
-    pool->prep = prep;
-    pool->refcnt = 1;
-    
-    return pool;
-}
-
-void
-cleanup_closure_pool(ClosurePool* pool)
-{
-    Memory* memory;
-    
-    for (memory = pool->blocks; memory != NULL; ) {
-        Memory* next = memory->next;
-        freePage(memory->code);
-        free(memory->data);
-        free(memory);
-        memory = next;
-    }
-    xfree(pool);
-}
-
-void
-rbffi_ClosurePool_Free(ClosurePool* pool)
-{
-    if (pool != NULL) {
-        long refcnt = --(pool->refcnt);
-        if (refcnt == 0) {
-            cleanup_closure_pool(pool);
-        }
-    }
-}
-
-Closure*
-rbffi_Closure_Alloc(ClosurePool* pool)
-{
-    Closure *list = NULL;
-    Memory* block = NULL;
-    caddr_t code = NULL;
-    char errmsg[256];
-    int nclosures;
-    long trampolineSize;
-    int i;
-
-    if (pool->list != NULL) {
-        Closure* closure = pool->list;
-        pool->list = pool->list->next;
-        pool->refcnt++;
-    
-        return closure;
-    }
-
-    trampolineSize = roundup(pool->closureSize, 8);
-    nclosures = (int) (pageSize / trampolineSize);
-    block = calloc(1, sizeof(*block));
-    list = calloc(nclosures, sizeof(*list));
-    code = allocatePage();
-    
-    if (block == NULL || list == NULL || code == NULL) {
-        snprintf(errmsg, sizeof(errmsg), "failed to allocate a page. errno=%d (%s)", errno, strerror(errno));
-        goto error;
-    }
-    
-    for (i = 0; i < nclosures; ++i) {
-        Closure* closure = &list[i];
-        closure->next = &list[i + 1];
-        closure->pool = pool;
-        closure->code = (code + (i * trampolineSize));
-
-        if (!(*pool->prep)(pool->ctx, closure->code, closure, errmsg, sizeof(errmsg))) {
-            goto error;
-        }
-    }
-
-    if (!protectPage(code)) {
-        goto error;
-    }
-
-    /* Track the allocated page + Closure memory area */
-    block->data = list;
-    block->code = code;
-    block->next = pool->blocks;
-    pool->blocks = block;
-
-    /* Thread the new block onto the free list, apart from the first one. */
-    list[nclosures - 1].next = pool->list;
-    pool->list = list->next;
-    pool->refcnt++;
-
-    /* Use the first one as the new handle */
-    return list;
-
-error:
-    free(block);
-    free(list);
-    if (code != NULL) {
-        freePage(code);
-    }
-    
-
-    rb_raise(rb_eRuntimeError, "%s", errmsg);
-    return NULL;
-}
-
-void
-rbffi_Closure_Free(Closure* closure)
-{
-    if (closure != NULL) {
-        ClosurePool* pool = closure->pool;
-        long refcnt;
-        /* Just push it on the front of the free list */
-        closure->next = pool->list;
-        pool->list = closure;
-        refcnt = --(pool->refcnt);
-        if (refcnt == 0) {
-            cleanup_closure_pool(pool);
-        }
-    }
-}
-
-void*
-rbffi_Closure_CodeAddress(Closure* handle)
-{
-    return handle->code;
-}
-
-
-static long
-getPageSize()
-{
-#if !defined(__CYGWIN__) && (defined(_WIN32) || defined(__WIN32__))
-    SYSTEM_INFO si;
-    GetSystemInfo(&si);
-    return si.dwPageSize;
-#else
-    return sysconf(_SC_PAGESIZE);
-#endif
-}
-
-static void*
-allocatePage(void)
-{
-#if !defined(__CYGWIN__) && (defined(_WIN32) || defined(__WIN32__))
-    return VirtualAlloc(NULL, pageSize, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
-#else
-    caddr_t page = mmap(NULL, pageSize, PROT_READ | PROT_WRITE, MAP_ANON | MAP_PRIVATE, -1, 0);
-    return (page != (caddr_t) -1) ? page : NULL;
-#endif
-}
-
-static bool
-freePage(void *addr)
-{
-#if !defined(__CYGWIN__) && (defined(_WIN32) || defined(__WIN32__))
-    return VirtualFree(addr, 0, MEM_RELEASE);
-#else
-    return munmap(addr, pageSize) == 0;
-#endif
-}
-
-static bool
-protectPage(void* page)
-{
-#if !defined(__CYGWIN__) && (defined(_WIN32) || defined(__WIN32__))
-    DWORD oldProtect;
-    return VirtualProtect(page, pageSize, PAGE_EXECUTE_READ, &oldProtect);
-#else
-    return mprotect(page, pageSize, PROT_READ | PROT_EXEC) == 0;
-#endif
-}
-
-void
-rbffi_ClosurePool_Init(VALUE module)
-{
-    pageSize = getPageSize();
-}
-
diff --git a/ext/ffi_c/Function.c b/ext/ffi_c/Function.c
index b44a03b..398dd20 100644
--- a/ext/ffi_c/Function.c
+++ b/ext/ffi_c/Function.c
@@ -65,7 +65,7 @@
 #include "Type.h"
 #include "LastError.h"
 #include "Call.h"
-#include "ClosurePool.h"
+#include "Closure.h"
 #include "MappedType.h"
 #include "Thread.h"
 #include "LongDouble.h"
@@ -309,6 +309,7 @@ static VALUE
 function_init(VALUE self, VALUE rbFunctionInfo, VALUE rbProc)
 {
     Function* fn = NULL;
+    ffi_status ffiStatus;
 
     Data_Get_Struct(self, Function, fn);
 
@@ -323,23 +324,28 @@ function_init(VALUE self, VALUE rbFunctionInfo, VALUE rbProc)
         fn->base.rbParent = rbProc;
 
     } else if (rb_obj_is_kind_of(rbProc, rb_cProc) || rb_respond_to(rbProc, id_call)) {
-        if (fn->info->closurePool == NULL) {
-            fn->info->closurePool = rbffi_ClosurePool_New(sizeof(ffi_closure), callback_prep, fn->info);
-            if (fn->info->closurePool == NULL) {
-                rb_raise(rb_eNoMemError, "failed to create closure pool");
-            }
-        }
-
 #if defined(DEFER_ASYNC_CALLBACK)
         if (async_cb_thread == Qnil) {
             async_cb_thread = rb_thread_create(async_cb_event, NULL);
         }
 #endif
 
-        fn->closure = rbffi_Closure_Alloc(fn->info->closurePool);
+        fn->closure = rbffi_Closure_Alloc();
         fn->closure->info = fn;
-        fn->base.memory.address = fn->closure->code;
+
+        ffiStatus = ffi_prep_closure_loc(fn->closure->libffi_closure,
+                &fn->info->ffi_cif, /* callback signature */
+                callback_invoke,
+                fn->closure, /* user_data for callback_invoke */
+                fn->closure->libffi_trampoline);
+        if (ffiStatus != FFI_OK) {
+            rb_raise(rb_eRuntimeError, "ffi_prep_closure_loc in function_init failed.  status=%#x",
+                    ffiStatus);
+        }
+
+        fn->base.memory.address = fn->closure->libffi_trampoline;
         fn->base.memory.size = sizeof(*fn->closure);
+
         fn->autorelease = true;
 
     } else {
@@ -858,21 +864,6 @@ save_callback_exception(void* data, VALUE exc)
     return Qnil;
 }
 
-static bool
-callback_prep(void* ctx, void* code, Closure* closure, char* errmsg, size_t errmsgsize)
-{
-    FunctionType* fnInfo = (FunctionType *) ctx;
-    ffi_status ffiStatus;
-
-    ffiStatus = ffi_prep_closure(code, &fnInfo->ffi_cif, callback_invoke, closure);
-    if (ffiStatus != FFI_OK) {
-        snprintf(errmsg, errmsgsize, "ffi_prep_closure failed.  status=%#x", ffiStatus);
-        return false;
-    }
-
-    return true;
-}
-
 void
 rbffi_Function_Init(VALUE moduleFFI)
 {
diff --git a/ext/ffi_c/Function.h b/ext/ffi_c/Function.h
index 052aaf6..4715cff 100644
--- a/ext/ffi_c/Function.h
+++ b/ext/ffi_c/Function.h
@@ -46,7 +46,7 @@ typedef struct FunctionType_ FunctionType;
 
 #include "Type.h"
 #include "Call.h"
-#include "ClosurePool.h"
+#include "Closure.h"
 
 struct FunctionType_ {
     Type type; /* The native type of a FunctionInfo object */
@@ -60,7 +60,6 @@ struct FunctionType_ {
     ffi_type** ffiParameterTypes;
     ffi_cif ffi_cif;
     Invoker invoke;
-    ClosurePool* closurePool;
     int parameterCount;
     int flags;
     ffi_abi abi;
diff --git a/ext/ffi_c/FunctionInfo.c b/ext/ffi_c/FunctionInfo.c
index 8085c87..a2ed83f 100644
--- a/ext/ffi_c/FunctionInfo.c
+++ b/ext/ffi_c/FunctionInfo.c
@@ -72,7 +72,6 @@ fntype_allocate(VALUE klass)
     fnInfo->rbParameterTypes = Qnil;
     fnInfo->rbEnums = Qnil;
     fnInfo->invoke = rbffi_CallFunction;
-    fnInfo->closurePool = NULL;
 
     return obj;
 }
@@ -95,9 +94,6 @@ fntype_free(FunctionType* fnInfo)
     xfree(fnInfo->ffiParameterTypes);
     xfree(fnInfo->nativeParameterTypes);
     xfree(fnInfo->callbackParameters);
-    if (fnInfo->closurePool != NULL) {
-        rbffi_ClosurePool_Free(fnInfo->closurePool);
-    }
     xfree(fnInfo);
 }
 
diff --git a/ext/ffi_c/MethodHandle.c b/ext/ffi_c/MethodHandle.c
index 70efb72..4be3e9e 100644
--- a/ext/ffi_c/MethodHandle.c
+++ b/ext/ffi_c/MethodHandle.c
@@ -26,30 +26,6 @@
  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
-#ifndef _MSC_VER
-#include <sys/param.h>
-#endif
-#include <sys/types.h>
-#ifndef _WIN32
-# include <sys/mman.h>
-#endif
-#include <stdio.h>
-#ifndef _MSC_VER
-# include <stdint.h>
-# include <stdbool.h>
-#else
-# include "win32/stdint.h"
-# include "win32/stdbool.h"
-#endif
-#ifndef _WIN32
-# include <unistd.h>
-#endif
-#include <errno.h>
-#include <ruby.h>
-#if defined(HAVE_NATIVETHREAD) && !defined(_WIN32) && !defined(__WIN32__)
-# include <pthread.h>
-#endif
-
 #include <ffi.h>
 #include "rbffi.h"
 #include "compat.h"
@@ -59,79 +35,16 @@
 #include "Type.h"
 #include "LastError.h"
 #include "Call.h"
-#include "ClosurePool.h"
+#include "Closure.h"
 #include "MethodHandle.h"
 
-
-#define MAX_METHOD_FIXED_ARITY (6)
-
-#ifndef roundup
-#  define roundup(x, y)   ((((x)+((y)-1))/(y))*(y))
-#endif
-#ifdef _WIN32
-  typedef char* caddr_t;
-#endif
-
-#ifdef USE_RAW
-#  define METHOD_CLOSURE ffi_raw_closure
-#  define METHOD_PARAMS ffi_raw*
-#else
-#  define METHOD_CLOSURE ffi_closure
-#  define METHOD_PARAMS void**
-#endif
-
-
-
-static bool prep_trampoline(void* ctx, void* code, Closure* closure, char* errmsg, size_t errmsgsize);
-static long trampoline_size(void);
-
-#if defined(__x86_64__) && (defined(__linux__) || defined(__APPLE__))
-# define CUSTOM_TRAMPOLINE 1
-#endif
-
+#define METHOD_CLOSURE ffi_closure
+#define METHOD_PARAMS void**
 
 struct MethodHandle {
     Closure* closure;
 };
 
-static ClosurePool* defaultClosurePool;
-
-
-MethodHandle*
-rbffi_MethodHandle_Alloc(FunctionType* fnInfo, void* function)
-{
-    MethodHandle* handle;
-    Closure* closure = rbffi_Closure_Alloc(defaultClosurePool);
-    if (closure == NULL) {
-        rb_raise(rb_eNoMemError, "failed to allocate closure from pool");
-        return NULL;
-    }
-
-    handle = xcalloc(1, sizeof(*handle));
-    handle->closure = closure;
-    closure->info = fnInfo;
-    closure->function = function;
-
-    return handle;
-}
-
-void
-rbffi_MethodHandle_Free(MethodHandle* handle)
-{
-    if (handle != NULL) {
-        rbffi_Closure_Free(handle->closure);
-    }
-}
-
-void*
-rbffi_MethodHandle_CodeAddress(MethodHandle* handle)
-{
-    return handle->closure->code;
-}
-
-#ifndef CUSTOM_TRAMPOLINE
-static void attached_method_invoke(ffi_cif* cif, void* retval, METHOD_PARAMS parameters, void* user_data);
-
 static ffi_type* methodHandleParamTypes[] = {
     &ffi_type_sint,
     &ffi_type_pointer,
@@ -140,219 +53,71 @@ static ffi_type* methodHandleParamTypes[] = {
 
 static ffi_cif mh_cif;
 
-static bool
-prep_trampoline(void* ctx, void* code, Closure* closure, char* errmsg, size_t errmsgsize)
-{
-    ffi_status ffiStatus;
-
-#if defined(USE_RAW)
-    ffiStatus = ffi_prep_raw_closure(code, &mh_cif, attached_method_invoke, closure);
-#else
-    ffiStatus = ffi_prep_closure(code, &mh_cif, attached_method_invoke, closure);
-#endif
-    if (ffiStatus != FFI_OK) {
-        snprintf(errmsg, errmsgsize, "ffi_prep_closure failed.  status=%#x", ffiStatus);
-        return false;
-    }
-
-    return true;
-}
-
-
-static long
-trampoline_size(void)
-{
-    return sizeof(METHOD_CLOSURE);
-}
-
-/*
- * attached_method_invoke is used functions with more than 6 parameters, or
- * with struct param or return values
- */
 static void
 attached_method_invoke(ffi_cif* cif, void* mretval, METHOD_PARAMS parameters, void* user_data)
 {
     Closure* handle =  (Closure *) user_data;
     FunctionType* fnInfo = (FunctionType *) handle->info;
 
-#ifdef USE_RAW
-    int argc = parameters[0].sint;
-    VALUE* argv = *(VALUE **) &parameters[1];
-#else
     int argc = *(int *) parameters[0];
     VALUE* argv = *(VALUE **) parameters[1];
-#endif
 
     *(VALUE *) mretval = (*fnInfo->invoke)(argc, argv, handle->function, fnInfo);
 }
 
-#endif
-
-
-
-#if defined(CUSTOM_TRAMPOLINE)
-#if defined(__x86_64__)
-
-static VALUE custom_trampoline(int argc, VALUE* argv, VALUE self, Closure*);
-
-#define TRAMPOLINE_CTX_MAGIC (0xfee1deadcafebabe)
-#define TRAMPOLINE_FUN_MAGIC (0xfeedfacebeeff00d)
-
-/*
- * This is a hand-coded trampoline to speedup entry from ruby to the FFI translation
- * layer for x86_64 arches.
- *
- * Since a ruby function has exactly 3 arguments, and the first 6 arguments are
- * passed in registers for x86_64, we can tack on a context pointer by simply
- * putting a value in %rcx, then jumping to the C trampoline code.
- *
- * This results in approx a 30% speedup for x86_64 FFI dispatch
- */
-__asm__(
-    ".text\n\t"
-    ".globl ffi_trampoline\n\t"
-    ".globl _ffi_trampoline\n\t"
-    "ffi_trampoline:\n\t"
-    "_ffi_trampoline:\n\t"
-    "movabsq $0xfee1deadcafebabe, %rcx\n\t"
-    "movabsq $0xfeedfacebeeff00d, %r11\n\t"
-    "jmpq *%r11\n\t"
-    ".globl ffi_trampoline_end\n\t"
-    "ffi_trampoline_end:\n\t"
-    ".globl _ffi_trampoline_end\n\t"
-    "_ffi_trampoline_end:\n\t"
-);
-
-static VALUE
-custom_trampoline(int argc, VALUE* argv, VALUE self, Closure* handle)
-{
-    FunctionType* fnInfo = (FunctionType *) handle->info;
-    VALUE rbReturnValue;
-
-    RB_GC_GUARD(rbReturnValue) = (*fnInfo->invoke)(argc, argv, handle->function, fnInfo);
-    RB_GC_GUARD(self);
-
-    return rbReturnValue;
-}
-
-#elif defined(__i386__) && 0
-
-static VALUE custom_trampoline(caddr_t args, Closure*);
-#define TRAMPOLINE_CTX_MAGIC (0xfee1dead)
-#define TRAMPOLINE_FUN_MAGIC (0xbeefcafe)
-
-/*
- * This is a hand-coded trampoline to speed-up entry from ruby to the FFI translation
- * layer for i386 arches.
- *
- * This does not make a discernible difference vs a raw closure, so for now,
- * it is not enabled.
- */
-__asm__(
-    ".text\n\t"
-    ".globl ffi_trampoline\n\t"
-    ".globl _ffi_trampoline\n\t"
-    "ffi_trampoline:\n\t"
-    "_ffi_trampoline:\n\t"
-    "subl    $12, %esp\n\t"
-    "leal    16(%esp), %eax\n\t"
-    "movl    %eax, (%esp)\n\t"
-    "movl    $0xfee1dead, 4(%esp)\n\t"
-    "movl    $0xbeefcafe, %eax\n\t"
-    "call    *%eax\n\t"
-    "addl    $12, %esp\n\t"
-    "ret\n\t"
-    ".globl ffi_trampoline_end\n\t"
-    "ffi_trampoline_end:\n\t"
-    ".globl _ffi_trampoline_end\n\t"
-    "_ffi_trampoline_end:\n\t"
-);
-
-static VALUE
-custom_trampoline(caddr_t args, Closure* handle)
+MethodHandle*
+rbffi_MethodHandle_Alloc(FunctionType* fnInfo, void* function)
 {
-    FunctionType* fnInfo = (FunctionType *) handle->info;
-    return (*fnInfo->invoke)(*(int *) args, *(VALUE **) (args + 4), handle->function, fnInfo);
-}
-
-#endif /* __x86_64__ else __i386__ */
-
-extern void ffi_trampoline(int argc, VALUE* argv, VALUE self);
-extern void ffi_trampoline_end(void);
-static int trampoline_offsets(long *, long *);
-
-static long trampoline_ctx_offset, trampoline_func_offset;
+    ffi_status ffiStatus;
+    MethodHandle* handle;
+    Closure* closure;
 
-static long
-trampoline_offset(int off, const long value)
-{
-    caddr_t ptr;
-    for (ptr = (caddr_t) &ffi_trampoline + off; ptr < (caddr_t) &ffi_trampoline_end; ++ptr) {
-        if (*(long *) ptr == value) {
-            return ptr - (caddr_t) &ffi_trampoline;
-        }
+    closure = rbffi_Closure_Alloc();
+    if (closure == NULL) {
+        rb_raise(rb_eNoMemError, "failed to allocate closure from pool");
+        return NULL;
     }
+    closure->info = fnInfo;
+    closure->function = function;
 
-    return -1;
-}
-
-static int
-trampoline_offsets(long* ctxOffset, long* fnOffset)
-{
-    *ctxOffset = trampoline_offset(0, TRAMPOLINE_CTX_MAGIC);
-    if (*ctxOffset == -1) {
-        return -1;
+    ffiStatus = ffi_prep_closure_loc(closure->libffi_closure,
+        &mh_cif, /* method signature */
+        attached_method_invoke,
+        closure, /* user_data for attached_method_invoke */
+        closure->libffi_trampoline);
+    if (ffiStatus != FFI_OK) {
+        rb_raise(rb_eRuntimeError, "ffi_prep_closure_loc failed.  status=%#x", ffiStatus);
+        return false;
     }
 
-    *fnOffset = trampoline_offset(0, TRAMPOLINE_FUN_MAGIC);
-    if (*fnOffset == -1) {
-        return -1;
-    }
+    handle = xcalloc(1, sizeof(*handle));
+    handle->closure = closure;
 
-    return 0;
+    return handle;
 }
 
-static bool
-prep_trampoline(void* ctx, void* code, Closure* closure, char* errmsg, size_t errmsgsize)
+void
+rbffi_MethodHandle_Free(MethodHandle* handle)
 {
-    caddr_t ptr = (caddr_t) code;
-
-    memcpy(ptr, &ffi_trampoline, trampoline_size());
-    /* Patch the context and function addresses into the stub code */
-    *(intptr_t *)(ptr + trampoline_ctx_offset) = (intptr_t) closure;
-    *(intptr_t *)(ptr + trampoline_func_offset) = (intptr_t) custom_trampoline;
-
-    return true;
+    if (handle != NULL) {
+        rbffi_Closure_Free(handle->closure);
+    }
 }
 
-static long
-trampoline_size(void)
+void*
+rbffi_MethodHandle_CodeAddress(MethodHandle* handle)
 {
-    return (caddr_t) &ffi_trampoline_end - (caddr_t) &ffi_trampoline;
+    return handle->closure->libffi_trampoline;
 }
 
-#endif /* CUSTOM_TRAMPOLINE */
-
-
 void
 rbffi_MethodHandle_Init(VALUE module)
 {
-#ifndef CUSTOM_TRAMPOLINE
     ffi_status ffiStatus;
-#endif
 
-    defaultClosurePool = rbffi_ClosurePool_New((int) trampoline_size(), prep_trampoline, NULL);
-
-#if defined(CUSTOM_TRAMPOLINE)
-    if (trampoline_offsets(&trampoline_ctx_offset, &trampoline_func_offset) != 0) {
-        rb_raise(rb_eFatal, "Could not locate offsets in trampoline code");
-    }
-#else
     ffiStatus = ffi_prep_cif(&mh_cif, FFI_DEFAULT_ABI, 3, &ffi_type_ulong,
             methodHandleParamTypes);
     if (ffiStatus != FFI_OK) {
         rb_raise(rb_eFatal, "ffi_prep_cif failed.  status=%#x", ffiStatus);
     }
-
-#endif
 }
diff --git a/ext/ffi_c/ffi.c b/ext/ffi_c/ffi.c
index 22ea3bf..fe6315c 100644
--- a/ext/ffi_c/ffi.c
+++ b/ext/ffi_c/ffi.c
@@ -45,7 +45,7 @@
 #include "Types.h"
 #include "LastError.h"
 #include "Function.h"
-#include "ClosurePool.h"
+#include "Closure.h"
 #include "MethodHandle.h"
 #include "Call.h"
 #include "ArrayType.h"
@@ -76,7 +76,7 @@ Init_ffi_c(void)
     rbffi_ArrayType_Init(moduleFFI);
     rbffi_LastError_Init(moduleFFI);
     rbffi_Call_Init(moduleFFI);
-    rbffi_ClosurePool_Init(moduleFFI);
+    rbffi_Closure_Init(moduleFFI);
     rbffi_MethodHandle_Init(moduleFFI);
     rbffi_Platform_Init(moduleFFI);
     rbffi_AbstractMemory_Init(moduleFFI);
-- 
2.21.0

