ffi 1.9.24 → 1.9.25
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +8 -0
- data/README.md +2 -0
- data/ext/ffi_c/Call.c +22 -1
- data/ext/ffi_c/Call.h +9 -0
- data/ext/ffi_c/ClosurePool.c +283 -0
- data/ext/ffi_c/{Closure.h → ClosurePool.h} +23 -13
- data/ext/ffi_c/Function.c +25 -16
- data/ext/ffi_c/Function.h +2 -1
- data/ext/ffi_c/FunctionInfo.c +4 -0
- data/ext/ffi_c/MethodHandle.c +268 -33
- data/ext/ffi_c/ffi.c +2 -2
- data/lib/ffi/version.rb +1 -1
- metadata +4 -4
- data/ext/ffi_c/Closure.c +0 -54
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: cf13d7fccdcd65b73b5286e04fc25a174b7b855ab1803995eaa4564d5d65456a
|
|
4
|
+
data.tar.gz: 187c8d21dd770d08e7e123ead2a727fc3e9e384d35ff2b5d37fc3a0df712f37e
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 06eb5d5d2c033e0b7ade6d75957f835d7831aca9b492ac752e7d2b4760707ecb07981e1cd366f0059b67c1b2f3a9b5964e70388d123f4997efa0f5c691baede8
|
|
7
|
+
data.tar.gz: e050bf8673f3bb19afbe78646f18f452c4fa2d70fc2a8f9f8efb073cd0658f6a7e0f1737dd6a05076422533ecf22e9952f08d407bdd0480bbde31fd55eef52de
|
data/CHANGELOG.md
CHANGED
data/README.md
CHANGED
|
@@ -43,6 +43,8 @@ At a minimum, you will need:
|
|
|
43
43
|
* A C compiler (e.g. Xcode on OSX, gcc on everything else)
|
|
44
44
|
* libffi development library - this is commonly in the libffi-dev or libffi-devel
|
|
45
45
|
|
|
46
|
+
On Linux systems running with [PaX](https://en.wikipedia.org/wiki/PaX) (Gentoo, Alpine, etc.) FFI may trigger `mprotect` errors. You may need to disable [mprotect](https://en.wikibooks.org/wiki/Grsecurity/Appendix/Grsecurity_and_PaX_Configuration_Options#Restrict_mprotect.28.29) for ruby (`paxctl -m [/path/to/ruby]`) for the time being until a solution is found.
|
|
47
|
+
|
|
46
48
|
## Installation
|
|
47
49
|
|
|
48
50
|
From rubygems:
|
data/ext/ffi_c/Call.c
CHANGED
|
@@ -65,7 +65,28 @@
|
|
|
65
65
|
#include "Thread.h"
|
|
66
66
|
#include "LongDouble.h"
|
|
67
67
|
|
|
68
|
-
#
|
|
68
|
+
#ifdef USE_RAW
|
|
69
|
+
# ifndef __i386__
|
|
70
|
+
# error "RAW argument packing only supported on i386"
|
|
71
|
+
# endif
|
|
72
|
+
|
|
73
|
+
#define INT8_ADJ (4)
|
|
74
|
+
#define INT16_ADJ (4)
|
|
75
|
+
#define INT32_ADJ (4)
|
|
76
|
+
#define INT64_ADJ (8)
|
|
77
|
+
#define LONG_ADJ (sizeof(long))
|
|
78
|
+
#define FLOAT32_ADJ (4)
|
|
79
|
+
#define FLOAT64_ADJ (8)
|
|
80
|
+
#define ADDRESS_ADJ (sizeof(void *))
|
|
81
|
+
#define LONGDOUBLE_ADJ (ffi_type_longdouble.alignment)
|
|
82
|
+
|
|
83
|
+
#endif /* USE_RAW */
|
|
84
|
+
|
|
85
|
+
#ifdef USE_RAW
|
|
86
|
+
# define ADJ(p, a) ((p) = (FFIStorage*) (((char *) p) + a##_ADJ))
|
|
87
|
+
#else
|
|
88
|
+
# define ADJ(p, a) (++(p))
|
|
89
|
+
#endif
|
|
69
90
|
|
|
70
91
|
static void* callback_param(VALUE proc, VALUE cbinfo);
|
|
71
92
|
static inline void* getPointer(VALUE value, int type);
|
data/ext/ffi_c/Call.h
CHANGED
|
@@ -39,7 +39,16 @@
|
|
|
39
39
|
extern "C" {
|
|
40
40
|
#endif
|
|
41
41
|
|
|
42
|
+
#if defined(__i386__) && \
|
|
43
|
+
(defined(HAVE_RAW_API) || defined(USE_INTERNAL_LIBFFI)) && \
|
|
44
|
+
!defined(_WIN32) && !defined(__WIN32__)
|
|
45
|
+
# define USE_RAW
|
|
46
|
+
#endif
|
|
42
47
|
|
|
48
|
+
#if (defined(__i386__) || defined(__x86_64__)) && !(defined(_WIN32) || defined(__WIN32__))
|
|
49
|
+
# define BYPASS_FFI 1
|
|
50
|
+
#endif
|
|
51
|
+
|
|
43
52
|
typedef union {
|
|
44
53
|
#ifdef USE_RAW
|
|
45
54
|
signed int s8, s16, s32;
|
|
@@ -0,0 +1,283 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright (c) 2009, 2010 Wayne Meissner
|
|
3
|
+
* Copyright (c) 2008-2013, Ruby FFI project contributors
|
|
4
|
+
* All rights reserved.
|
|
5
|
+
*
|
|
6
|
+
* Redistribution and use in source and binary forms, with or without
|
|
7
|
+
* modification, are permitted provided that the following conditions are met:
|
|
8
|
+
* * Redistributions of source code must retain the above copyright
|
|
9
|
+
* notice, this list of conditions and the following disclaimer.
|
|
10
|
+
* * Redistributions in binary form must reproduce the above copyright
|
|
11
|
+
* notice, this list of conditions and the following disclaimer in the
|
|
12
|
+
* documentation and/or other materials provided with the distribution.
|
|
13
|
+
* * Neither the name of the Ruby FFI project nor the
|
|
14
|
+
* names of its contributors may be used to endorse or promote products
|
|
15
|
+
* derived from this software without specific prior written permission.
|
|
16
|
+
*
|
|
17
|
+
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
|
18
|
+
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
|
19
|
+
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
20
|
+
* DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
|
|
21
|
+
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
|
22
|
+
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
|
23
|
+
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
|
24
|
+
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
25
|
+
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
|
26
|
+
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
27
|
+
*/
|
|
28
|
+
|
|
29
|
+
#ifndef _MSC_VER
|
|
30
|
+
#include <sys/param.h>
|
|
31
|
+
#endif
|
|
32
|
+
#include <sys/types.h>
|
|
33
|
+
#if defined(__CYGWIN__) || !defined(_WIN32)
|
|
34
|
+
# include <sys/mman.h>
|
|
35
|
+
#endif
|
|
36
|
+
#include <stdio.h>
|
|
37
|
+
#ifndef _MSC_VER
|
|
38
|
+
# include <stdint.h>
|
|
39
|
+
# include <stdbool.h>
|
|
40
|
+
#else
|
|
41
|
+
# include "win32/stdbool.h"
|
|
42
|
+
# include "win32/stdint.h"
|
|
43
|
+
#endif
|
|
44
|
+
#if defined(__CYGWIN__) || !defined(_WIN32)
|
|
45
|
+
# include <unistd.h>
|
|
46
|
+
#else
|
|
47
|
+
# include <winsock2.h>
|
|
48
|
+
# define _WINSOCKAPI_
|
|
49
|
+
# include <windows.h>
|
|
50
|
+
#endif
|
|
51
|
+
#include <errno.h>
|
|
52
|
+
#include <ruby.h>
|
|
53
|
+
|
|
54
|
+
#if defined(_MSC_VER) && !defined(INT8_MIN)
|
|
55
|
+
# include "win32/stdint.h"
|
|
56
|
+
#endif
|
|
57
|
+
#include <ffi.h>
|
|
58
|
+
#include "rbffi.h"
|
|
59
|
+
#include "compat.h"
|
|
60
|
+
|
|
61
|
+
#include "Function.h"
|
|
62
|
+
#include "Types.h"
|
|
63
|
+
#include "Type.h"
|
|
64
|
+
#include "LastError.h"
|
|
65
|
+
#include "Call.h"
|
|
66
|
+
|
|
67
|
+
#include "ClosurePool.h"
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
#ifndef roundup
|
|
71
|
+
# define roundup(x, y) ((((x)+((y)-1))/(y))*(y))
|
|
72
|
+
#endif
|
|
73
|
+
#ifdef _WIN32
|
|
74
|
+
typedef char* caddr_t;
|
|
75
|
+
#endif
|
|
76
|
+
|
|
77
|
+
typedef struct Memory {
|
|
78
|
+
void* code;
|
|
79
|
+
void* data;
|
|
80
|
+
struct Memory* next;
|
|
81
|
+
} Memory;
|
|
82
|
+
|
|
83
|
+
struct ClosurePool_ {
|
|
84
|
+
void* ctx;
|
|
85
|
+
int closureSize;
|
|
86
|
+
bool (*prep)(void* ctx, void *code, Closure* closure, char* errbuf, size_t errbufsize);
|
|
87
|
+
struct Memory* blocks; /* Keeps track of all the allocated memory for this pool */
|
|
88
|
+
Closure* list;
|
|
89
|
+
long refcnt;
|
|
90
|
+
};
|
|
91
|
+
|
|
92
|
+
static long pageSize;
|
|
93
|
+
|
|
94
|
+
static void* allocatePage(void);
|
|
95
|
+
static bool freePage(void *);
|
|
96
|
+
static bool protectPage(void *);
|
|
97
|
+
|
|
98
|
+
ClosurePool*
|
|
99
|
+
rbffi_ClosurePool_New(int closureSize,
|
|
100
|
+
bool (*prep)(void* ctx, void *code, Closure* closure, char* errbuf, size_t errbufsize),
|
|
101
|
+
void* ctx)
|
|
102
|
+
{
|
|
103
|
+
ClosurePool* pool;
|
|
104
|
+
|
|
105
|
+
pool = xcalloc(1, sizeof(*pool));
|
|
106
|
+
pool->closureSize = closureSize;
|
|
107
|
+
pool->ctx = ctx;
|
|
108
|
+
pool->prep = prep;
|
|
109
|
+
pool->refcnt = 1;
|
|
110
|
+
|
|
111
|
+
return pool;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
void
|
|
115
|
+
cleanup_closure_pool(ClosurePool* pool)
|
|
116
|
+
{
|
|
117
|
+
Memory* memory;
|
|
118
|
+
|
|
119
|
+
for (memory = pool->blocks; memory != NULL; ) {
|
|
120
|
+
Memory* next = memory->next;
|
|
121
|
+
freePage(memory->code);
|
|
122
|
+
free(memory->data);
|
|
123
|
+
free(memory);
|
|
124
|
+
memory = next;
|
|
125
|
+
}
|
|
126
|
+
xfree(pool);
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
void
|
|
130
|
+
rbffi_ClosurePool_Free(ClosurePool* pool)
|
|
131
|
+
{
|
|
132
|
+
if (pool != NULL) {
|
|
133
|
+
long refcnt = --(pool->refcnt);
|
|
134
|
+
if (refcnt == 0) {
|
|
135
|
+
cleanup_closure_pool(pool);
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
Closure*
|
|
141
|
+
rbffi_Closure_Alloc(ClosurePool* pool)
|
|
142
|
+
{
|
|
143
|
+
Closure *list = NULL;
|
|
144
|
+
Memory* block = NULL;
|
|
145
|
+
caddr_t code = NULL;
|
|
146
|
+
char errmsg[256];
|
|
147
|
+
int nclosures;
|
|
148
|
+
long trampolineSize;
|
|
149
|
+
int i;
|
|
150
|
+
|
|
151
|
+
if (pool->list != NULL) {
|
|
152
|
+
Closure* closure = pool->list;
|
|
153
|
+
pool->list = pool->list->next;
|
|
154
|
+
pool->refcnt++;
|
|
155
|
+
|
|
156
|
+
return closure;
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
trampolineSize = roundup(pool->closureSize, 8);
|
|
160
|
+
nclosures = (int) (pageSize / trampolineSize);
|
|
161
|
+
block = calloc(1, sizeof(*block));
|
|
162
|
+
list = calloc(nclosures, sizeof(*list));
|
|
163
|
+
code = allocatePage();
|
|
164
|
+
|
|
165
|
+
if (block == NULL || list == NULL || code == NULL) {
|
|
166
|
+
snprintf(errmsg, sizeof(errmsg), "failed to allocate a page. errno=%d (%s)", errno, strerror(errno));
|
|
167
|
+
goto error;
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
for (i = 0; i < nclosures; ++i) {
|
|
171
|
+
Closure* closure = &list[i];
|
|
172
|
+
closure->next = &list[i + 1];
|
|
173
|
+
closure->pool = pool;
|
|
174
|
+
closure->code = (code + (i * trampolineSize));
|
|
175
|
+
|
|
176
|
+
if (!(*pool->prep)(pool->ctx, closure->code, closure, errmsg, sizeof(errmsg))) {
|
|
177
|
+
goto error;
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
if (!protectPage(code)) {
|
|
182
|
+
goto error;
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
/* Track the allocated page + Closure memory area */
|
|
186
|
+
block->data = list;
|
|
187
|
+
block->code = code;
|
|
188
|
+
block->next = pool->blocks;
|
|
189
|
+
pool->blocks = block;
|
|
190
|
+
|
|
191
|
+
/* Thread the new block onto the free list, apart from the first one. */
|
|
192
|
+
list[nclosures - 1].next = pool->list;
|
|
193
|
+
pool->list = list->next;
|
|
194
|
+
pool->refcnt++;
|
|
195
|
+
|
|
196
|
+
/* Use the first one as the new handle */
|
|
197
|
+
return list;
|
|
198
|
+
|
|
199
|
+
error:
|
|
200
|
+
free(block);
|
|
201
|
+
free(list);
|
|
202
|
+
if (code != NULL) {
|
|
203
|
+
freePage(code);
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
|
|
207
|
+
rb_raise(rb_eRuntimeError, "%s", errmsg);
|
|
208
|
+
return NULL;
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
void
|
|
212
|
+
rbffi_Closure_Free(Closure* closure)
|
|
213
|
+
{
|
|
214
|
+
if (closure != NULL) {
|
|
215
|
+
ClosurePool* pool = closure->pool;
|
|
216
|
+
long refcnt;
|
|
217
|
+
/* Just push it on the front of the free list */
|
|
218
|
+
closure->next = pool->list;
|
|
219
|
+
pool->list = closure;
|
|
220
|
+
refcnt = --(pool->refcnt);
|
|
221
|
+
if (refcnt == 0) {
|
|
222
|
+
cleanup_closure_pool(pool);
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
void*
|
|
228
|
+
rbffi_Closure_CodeAddress(Closure* handle)
|
|
229
|
+
{
|
|
230
|
+
return handle->code;
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
|
|
234
|
+
static long
|
|
235
|
+
getPageSize()
|
|
236
|
+
{
|
|
237
|
+
#if !defined(__CYGWIN__) && (defined(_WIN32) || defined(__WIN32__))
|
|
238
|
+
SYSTEM_INFO si;
|
|
239
|
+
GetSystemInfo(&si);
|
|
240
|
+
return si.dwPageSize;
|
|
241
|
+
#else
|
|
242
|
+
return sysconf(_SC_PAGESIZE);
|
|
243
|
+
#endif
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
static void*
|
|
247
|
+
allocatePage(void)
|
|
248
|
+
{
|
|
249
|
+
#if !defined(__CYGWIN__) && (defined(_WIN32) || defined(__WIN32__))
|
|
250
|
+
return VirtualAlloc(NULL, pageSize, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
|
|
251
|
+
#else
|
|
252
|
+
caddr_t page = mmap(NULL, pageSize, PROT_READ | PROT_WRITE, MAP_ANON | MAP_PRIVATE, -1, 0);
|
|
253
|
+
return (page != (caddr_t) -1) ? page : NULL;
|
|
254
|
+
#endif
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
static bool
|
|
258
|
+
freePage(void *addr)
|
|
259
|
+
{
|
|
260
|
+
#if !defined(__CYGWIN__) && (defined(_WIN32) || defined(__WIN32__))
|
|
261
|
+
return VirtualFree(addr, 0, MEM_RELEASE);
|
|
262
|
+
#else
|
|
263
|
+
return munmap(addr, pageSize) == 0;
|
|
264
|
+
#endif
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
static bool
|
|
268
|
+
protectPage(void* page)
|
|
269
|
+
{
|
|
270
|
+
#if !defined(__CYGWIN__) && (defined(_WIN32) || defined(__WIN32__))
|
|
271
|
+
DWORD oldProtect;
|
|
272
|
+
return VirtualProtect(page, pageSize, PAGE_EXECUTE_READ, &oldProtect);
|
|
273
|
+
#else
|
|
274
|
+
return mprotect(page, pageSize, PROT_READ | PROT_EXEC) == 0;
|
|
275
|
+
#endif
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
void
|
|
279
|
+
rbffi_ClosurePool_Init(VALUE module)
|
|
280
|
+
{
|
|
281
|
+
pageSize = getPageSize();
|
|
282
|
+
}
|
|
283
|
+
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/*
|
|
2
2
|
* Copyright (c) 2009, 2010 Wayne Meissner
|
|
3
|
-
* Copyright (c) 2008-
|
|
3
|
+
* Copyright (c) 2008-2013, Ruby FFI project contributors
|
|
4
4
|
* All rights reserved.
|
|
5
5
|
*
|
|
6
6
|
* Redistribution and use in source and binary forms, with or without
|
|
@@ -26,22 +26,32 @@
|
|
|
26
26
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
27
27
|
*/
|
|
28
28
|
|
|
29
|
-
#ifndef
|
|
30
|
-
#define
|
|
29
|
+
#ifndef RUBYFFI_CLOSUREPOOL_H
|
|
30
|
+
#define RUBYFFI_CLOSUREPOOL_H
|
|
31
31
|
|
|
32
|
-
|
|
32
|
+
typedef struct ClosurePool_ ClosurePool;
|
|
33
|
+
typedef struct Closure_ Closure;
|
|
33
34
|
|
|
34
|
-
|
|
35
|
-
void* info;
|
|
36
|
-
void* function;
|
|
37
|
-
void*
|
|
38
|
-
|
|
39
|
-
|
|
35
|
+
struct Closure_ {
|
|
36
|
+
void* info; /* opaque handle for storing closure-instance specific data */
|
|
37
|
+
void* function; /* closure-instance specific function, called by custom trampoline */
|
|
38
|
+
void* code; /* The native trampoline code location */
|
|
39
|
+
struct ClosurePool_* pool;
|
|
40
|
+
Closure* next;
|
|
41
|
+
};
|
|
40
42
|
|
|
41
|
-
|
|
43
|
+
void rbffi_ClosurePool_Init(VALUE module);
|
|
44
|
+
|
|
45
|
+
ClosurePool* rbffi_ClosurePool_New(int closureSize,
|
|
46
|
+
bool (*prep)(void* ctx, void *code, Closure* closure, char* errbuf, size_t errbufsize),
|
|
47
|
+
void* ctx);
|
|
48
|
+
|
|
49
|
+
void rbffi_ClosurePool_Free(ClosurePool *);
|
|
50
|
+
|
|
51
|
+
Closure* rbffi_Closure_Alloc(ClosurePool *);
|
|
42
52
|
void rbffi_Closure_Free(Closure *);
|
|
43
53
|
|
|
44
|
-
void
|
|
54
|
+
void* rbffi_Closure_GetCodeAddress(Closure *);
|
|
45
55
|
|
|
46
|
-
#endif /*
|
|
56
|
+
#endif /* RUBYFFI_CLOSUREPOOL_H */
|
|
47
57
|
|
data/ext/ffi_c/Function.c
CHANGED
|
@@ -67,7 +67,7 @@
|
|
|
67
67
|
#include "Type.h"
|
|
68
68
|
#include "LastError.h"
|
|
69
69
|
#include "Call.h"
|
|
70
|
-
#include "
|
|
70
|
+
#include "ClosurePool.h"
|
|
71
71
|
#include "MappedType.h"
|
|
72
72
|
#include "Thread.h"
|
|
73
73
|
#include "LongDouble.h"
|
|
@@ -300,7 +300,6 @@ static VALUE
|
|
|
300
300
|
function_init(VALUE self, VALUE rbFunctionInfo, VALUE rbProc)
|
|
301
301
|
{
|
|
302
302
|
Function* fn = NULL;
|
|
303
|
-
ffi_status ffiStatus;
|
|
304
303
|
|
|
305
304
|
Data_Get_Struct(self, Function, fn);
|
|
306
305
|
|
|
@@ -315,6 +314,13 @@ function_init(VALUE self, VALUE rbFunctionInfo, VALUE rbProc)
|
|
|
315
314
|
fn->base.rbParent = rbProc;
|
|
316
315
|
|
|
317
316
|
} else if (rb_obj_is_kind_of(rbProc, rb_cProc) || rb_respond_to(rbProc, id_call)) {
|
|
317
|
+
if (fn->info->closurePool == NULL) {
|
|
318
|
+
fn->info->closurePool = rbffi_ClosurePool_New(sizeof(ffi_closure), callback_prep, fn->info);
|
|
319
|
+
if (fn->info->closurePool == NULL) {
|
|
320
|
+
rb_raise(rb_eNoMemError, "failed to create closure pool");
|
|
321
|
+
}
|
|
322
|
+
}
|
|
323
|
+
|
|
318
324
|
#if defined(DEFER_ASYNC_CALLBACK)
|
|
319
325
|
if (async_cb_thread == Qnil) {
|
|
320
326
|
#if !(defined(HAVE_RB_THREAD_BLOCKING_REGION) || defined(HAVE_RB_THREAD_CALL_WITHOUT_GVL)) && defined(_WIN32)
|
|
@@ -329,22 +335,10 @@ function_init(VALUE self, VALUE rbFunctionInfo, VALUE rbProc)
|
|
|
329
335
|
|
|
330
336
|
#endif
|
|
331
337
|
|
|
332
|
-
fn->closure = rbffi_Closure_Alloc();
|
|
338
|
+
fn->closure = rbffi_Closure_Alloc(fn->info->closurePool);
|
|
333
339
|
fn->closure->info = fn;
|
|
334
|
-
|
|
335
|
-
ffiStatus = ffi_prep_closure_loc(fn->closure->libffi_closure,
|
|
336
|
-
&fn->info->ffi_cif, /* callback signature */
|
|
337
|
-
callback_invoke,
|
|
338
|
-
fn->closure, /* user_data for callback_invoke */
|
|
339
|
-
fn->closure->libffi_trampoline);
|
|
340
|
-
if (ffiStatus != FFI_OK) {
|
|
341
|
-
rb_raise(rb_eRuntimeError, "ffi_prep_closure_loc in function_init failed. status=%#x",
|
|
342
|
-
ffiStatus);
|
|
343
|
-
}
|
|
344
|
-
|
|
345
|
-
fn->base.memory.address = fn->closure->libffi_trampoline;
|
|
340
|
+
fn->base.memory.address = fn->closure->code;
|
|
346
341
|
fn->base.memory.size = sizeof(*fn->closure);
|
|
347
|
-
|
|
348
342
|
fn->autorelease = true;
|
|
349
343
|
|
|
350
344
|
} else {
|
|
@@ -948,6 +942,21 @@ save_callback_exception(void* data, VALUE exc)
|
|
|
948
942
|
return Qnil;
|
|
949
943
|
}
|
|
950
944
|
|
|
945
|
+
static bool
|
|
946
|
+
callback_prep(void* ctx, void* code, Closure* closure, char* errmsg, size_t errmsgsize)
|
|
947
|
+
{
|
|
948
|
+
FunctionType* fnInfo = (FunctionType *) ctx;
|
|
949
|
+
ffi_status ffiStatus;
|
|
950
|
+
|
|
951
|
+
ffiStatus = ffi_prep_closure(code, &fnInfo->ffi_cif, callback_invoke, closure);
|
|
952
|
+
if (ffiStatus != FFI_OK) {
|
|
953
|
+
snprintf(errmsg, errmsgsize, "ffi_prep_closure failed. status=%#x", ffiStatus);
|
|
954
|
+
return false;
|
|
955
|
+
}
|
|
956
|
+
|
|
957
|
+
return true;
|
|
958
|
+
}
|
|
959
|
+
|
|
951
960
|
void
|
|
952
961
|
rbffi_Function_Init(VALUE moduleFFI)
|
|
953
962
|
{
|
data/ext/ffi_c/Function.h
CHANGED
|
@@ -46,7 +46,7 @@ typedef struct FunctionType_ FunctionType;
|
|
|
46
46
|
|
|
47
47
|
#include "Type.h"
|
|
48
48
|
#include "Call.h"
|
|
49
|
-
#include "
|
|
49
|
+
#include "ClosurePool.h"
|
|
50
50
|
|
|
51
51
|
struct FunctionType_ {
|
|
52
52
|
Type type; /* The native type of a FunctionInfo object */
|
|
@@ -60,6 +60,7 @@ struct FunctionType_ {
|
|
|
60
60
|
ffi_type** ffiParameterTypes;
|
|
61
61
|
ffi_cif ffi_cif;
|
|
62
62
|
Invoker invoke;
|
|
63
|
+
ClosurePool* closurePool;
|
|
63
64
|
int parameterCount;
|
|
64
65
|
int flags;
|
|
65
66
|
ffi_abi abi;
|
data/ext/ffi_c/FunctionInfo.c
CHANGED
|
@@ -72,6 +72,7 @@ fntype_allocate(VALUE klass)
|
|
|
72
72
|
fnInfo->rbParameterTypes = Qnil;
|
|
73
73
|
fnInfo->rbEnums = Qnil;
|
|
74
74
|
fnInfo->invoke = rbffi_CallFunction;
|
|
75
|
+
fnInfo->closurePool = NULL;
|
|
75
76
|
|
|
76
77
|
return obj;
|
|
77
78
|
}
|
|
@@ -94,6 +95,9 @@ fntype_free(FunctionType* fnInfo)
|
|
|
94
95
|
xfree(fnInfo->ffiParameterTypes);
|
|
95
96
|
xfree(fnInfo->nativeParameterTypes);
|
|
96
97
|
xfree(fnInfo->callbackParameters);
|
|
98
|
+
if (fnInfo->closurePool != NULL) {
|
|
99
|
+
rbffi_ClosurePool_Free(fnInfo->closurePool);
|
|
100
|
+
}
|
|
97
101
|
xfree(fnInfo);
|
|
98
102
|
}
|
|
99
103
|
|
data/ext/ffi_c/MethodHandle.c
CHANGED
|
@@ -26,6 +26,30 @@
|
|
|
26
26
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
27
27
|
*/
|
|
28
28
|
|
|
29
|
+
#ifndef _MSC_VER
|
|
30
|
+
#include <sys/param.h>
|
|
31
|
+
#endif
|
|
32
|
+
#include <sys/types.h>
|
|
33
|
+
#ifndef _WIN32
|
|
34
|
+
# include <sys/mman.h>
|
|
35
|
+
#endif
|
|
36
|
+
#include <stdio.h>
|
|
37
|
+
#ifndef _MSC_VER
|
|
38
|
+
# include <stdint.h>
|
|
39
|
+
# include <stdbool.h>
|
|
40
|
+
#else
|
|
41
|
+
# include "win32/stdint.h"
|
|
42
|
+
# include "win32/stdbool.h"
|
|
43
|
+
#endif
|
|
44
|
+
#ifndef _WIN32
|
|
45
|
+
# include <unistd.h>
|
|
46
|
+
#endif
|
|
47
|
+
#include <errno.h>
|
|
48
|
+
#include <ruby.h>
|
|
49
|
+
#if defined(HAVE_NATIVETHREAD) && !defined(_WIN32) && !defined(__WIN32__)
|
|
50
|
+
# include <pthread.h>
|
|
51
|
+
#endif
|
|
52
|
+
|
|
29
53
|
#include <ffi.h>
|
|
30
54
|
#include "rbffi.h"
|
|
31
55
|
#include "compat.h"
|
|
@@ -35,16 +59,79 @@
|
|
|
35
59
|
#include "Type.h"
|
|
36
60
|
#include "LastError.h"
|
|
37
61
|
#include "Call.h"
|
|
38
|
-
#include "
|
|
62
|
+
#include "ClosurePool.h"
|
|
39
63
|
#include "MethodHandle.h"
|
|
40
64
|
|
|
41
|
-
|
|
42
|
-
#define
|
|
65
|
+
|
|
66
|
+
#define MAX_METHOD_FIXED_ARITY (6)
|
|
67
|
+
|
|
68
|
+
#ifndef roundup
|
|
69
|
+
# define roundup(x, y) ((((x)+((y)-1))/(y))*(y))
|
|
70
|
+
#endif
|
|
71
|
+
#ifdef _WIN32
|
|
72
|
+
typedef char* caddr_t;
|
|
73
|
+
#endif
|
|
74
|
+
|
|
75
|
+
#ifdef USE_RAW
|
|
76
|
+
# define METHOD_CLOSURE ffi_raw_closure
|
|
77
|
+
# define METHOD_PARAMS ffi_raw*
|
|
78
|
+
#else
|
|
79
|
+
# define METHOD_CLOSURE ffi_closure
|
|
80
|
+
# define METHOD_PARAMS void**
|
|
81
|
+
#endif
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
static bool prep_trampoline(void* ctx, void* code, Closure* closure, char* errmsg, size_t errmsgsize);
|
|
86
|
+
static long trampoline_size(void);
|
|
87
|
+
|
|
88
|
+
#if defined(__x86_64__) && (defined(__linux__) || defined(__APPLE__))
|
|
89
|
+
# define CUSTOM_TRAMPOLINE 1
|
|
90
|
+
#endif
|
|
91
|
+
|
|
43
92
|
|
|
44
93
|
struct MethodHandle {
|
|
45
94
|
Closure* closure;
|
|
46
95
|
};
|
|
47
96
|
|
|
97
|
+
static ClosurePool* defaultClosurePool;
|
|
98
|
+
|
|
99
|
+
|
|
100
|
+
MethodHandle*
|
|
101
|
+
rbffi_MethodHandle_Alloc(FunctionType* fnInfo, void* function)
|
|
102
|
+
{
|
|
103
|
+
MethodHandle* handle;
|
|
104
|
+
Closure* closure = rbffi_Closure_Alloc(defaultClosurePool);
|
|
105
|
+
if (closure == NULL) {
|
|
106
|
+
rb_raise(rb_eNoMemError, "failed to allocate closure from pool");
|
|
107
|
+
return NULL;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
handle = xcalloc(1, sizeof(*handle));
|
|
111
|
+
handle->closure = closure;
|
|
112
|
+
closure->info = fnInfo;
|
|
113
|
+
closure->function = function;
|
|
114
|
+
|
|
115
|
+
return handle;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
void
|
|
119
|
+
rbffi_MethodHandle_Free(MethodHandle* handle)
|
|
120
|
+
{
|
|
121
|
+
if (handle != NULL) {
|
|
122
|
+
rbffi_Closure_Free(handle->closure);
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
void*
|
|
127
|
+
rbffi_MethodHandle_CodeAddress(MethodHandle* handle)
|
|
128
|
+
{
|
|
129
|
+
return handle->closure->code;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
#ifndef CUSTOM_TRAMPOLINE
|
|
133
|
+
static void attached_method_invoke(ffi_cif* cif, void* retval, METHOD_PARAMS parameters, void* user_data);
|
|
134
|
+
|
|
48
135
|
static ffi_type* methodHandleParamTypes[] = {
|
|
49
136
|
&ffi_type_sint,
|
|
50
137
|
&ffi_type_pointer,
|
|
@@ -53,71 +140,219 @@ static ffi_type* methodHandleParamTypes[] = {
|
|
|
53
140
|
|
|
54
141
|
static ffi_cif mh_cif;
|
|
55
142
|
|
|
143
|
+
static bool
|
|
144
|
+
prep_trampoline(void* ctx, void* code, Closure* closure, char* errmsg, size_t errmsgsize)
|
|
145
|
+
{
|
|
146
|
+
ffi_status ffiStatus;
|
|
147
|
+
|
|
148
|
+
#if defined(USE_RAW)
|
|
149
|
+
ffiStatus = ffi_prep_raw_closure(code, &mh_cif, attached_method_invoke, closure);
|
|
150
|
+
#else
|
|
151
|
+
ffiStatus = ffi_prep_closure(code, &mh_cif, attached_method_invoke, closure);
|
|
152
|
+
#endif
|
|
153
|
+
if (ffiStatus != FFI_OK) {
|
|
154
|
+
snprintf(errmsg, errmsgsize, "ffi_prep_closure failed. status=%#x", ffiStatus);
|
|
155
|
+
return false;
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
return true;
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
|
|
162
|
+
static long
|
|
163
|
+
trampoline_size(void)
|
|
164
|
+
{
|
|
165
|
+
return sizeof(METHOD_CLOSURE);
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
/*
|
|
169
|
+
* attached_method_invoke is used functions with more than 6 parameters, or
|
|
170
|
+
* with struct param or return values
|
|
171
|
+
*/
|
|
56
172
|
static void
|
|
57
173
|
attached_method_invoke(ffi_cif* cif, void* mretval, METHOD_PARAMS parameters, void* user_data)
|
|
58
174
|
{
|
|
59
175
|
Closure* handle = (Closure *) user_data;
|
|
60
176
|
FunctionType* fnInfo = (FunctionType *) handle->info;
|
|
61
177
|
|
|
178
|
+
#ifdef USE_RAW
|
|
179
|
+
int argc = parameters[0].sint;
|
|
180
|
+
VALUE* argv = *(VALUE **) ¶meters[1];
|
|
181
|
+
#else
|
|
62
182
|
int argc = *(int *) parameters[0];
|
|
63
183
|
VALUE* argv = *(VALUE **) parameters[1];
|
|
184
|
+
#endif
|
|
64
185
|
|
|
65
186
|
*(VALUE *) mretval = (*fnInfo->invoke)(argc, argv, handle->function, fnInfo);
|
|
66
187
|
}
|
|
67
188
|
|
|
68
|
-
|
|
69
|
-
|
|
189
|
+
#endif
|
|
190
|
+
|
|
191
|
+
|
|
192
|
+
|
|
193
|
+
#if defined(CUSTOM_TRAMPOLINE)
|
|
194
|
+
#if defined(__x86_64__)
|
|
195
|
+
|
|
196
|
+
static VALUE custom_trampoline(int argc, VALUE* argv, VALUE self, Closure*);
|
|
197
|
+
|
|
198
|
+
#define TRAMPOLINE_CTX_MAGIC (0xfee1deadcafebabe)
|
|
199
|
+
#define TRAMPOLINE_FUN_MAGIC (0xfeedfacebeeff00d)
|
|
200
|
+
|
|
201
|
+
/*
|
|
202
|
+
* This is a hand-coded trampoline to speedup entry from ruby to the FFI translation
|
|
203
|
+
* layer for x86_64 arches.
|
|
204
|
+
*
|
|
205
|
+
* Since a ruby function has exactly 3 arguments, and the first 6 arguments are
|
|
206
|
+
* passed in registers for x86_64, we can tack on a context pointer by simply
|
|
207
|
+
* putting a value in %rcx, then jumping to the C trampoline code.
|
|
208
|
+
*
|
|
209
|
+
* This results in approx a 30% speedup for x86_64 FFI dispatch
|
|
210
|
+
*/
|
|
211
|
+
__asm__(
|
|
212
|
+
".text\n\t"
|
|
213
|
+
".globl ffi_trampoline\n\t"
|
|
214
|
+
".globl _ffi_trampoline\n\t"
|
|
215
|
+
"ffi_trampoline:\n\t"
|
|
216
|
+
"_ffi_trampoline:\n\t"
|
|
217
|
+
"movabsq $0xfee1deadcafebabe, %rcx\n\t"
|
|
218
|
+
"movabsq $0xfeedfacebeeff00d, %r11\n\t"
|
|
219
|
+
"jmpq *%r11\n\t"
|
|
220
|
+
".globl ffi_trampoline_end\n\t"
|
|
221
|
+
"ffi_trampoline_end:\n\t"
|
|
222
|
+
".globl _ffi_trampoline_end\n\t"
|
|
223
|
+
"_ffi_trampoline_end:\n\t"
|
|
224
|
+
);
|
|
225
|
+
|
|
226
|
+
static VALUE
|
|
227
|
+
custom_trampoline(int argc, VALUE* argv, VALUE self, Closure* handle)
|
|
70
228
|
{
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
Closure* closure;
|
|
229
|
+
FunctionType* fnInfo = (FunctionType *) handle->info;
|
|
230
|
+
VALUE rbReturnValue;
|
|
74
231
|
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
232
|
+
RB_GC_GUARD(rbReturnValue) = (*fnInfo->invoke)(argc, argv, handle->function, fnInfo);
|
|
233
|
+
RB_GC_GUARD(self);
|
|
234
|
+
|
|
235
|
+
return rbReturnValue;
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
#elif defined(__i386__) && 0
|
|
239
|
+
|
|
240
|
+
static VALUE custom_trampoline(caddr_t args, Closure*);
|
|
241
|
+
#define TRAMPOLINE_CTX_MAGIC (0xfee1dead)
|
|
242
|
+
#define TRAMPOLINE_FUN_MAGIC (0xbeefcafe)
|
|
243
|
+
|
|
244
|
+
/*
|
|
245
|
+
* This is a hand-coded trampoline to speed-up entry from ruby to the FFI translation
|
|
246
|
+
* layer for i386 arches.
|
|
247
|
+
*
|
|
248
|
+
* This does not make a discernible difference vs a raw closure, so for now,
|
|
249
|
+
* it is not enabled.
|
|
250
|
+
*/
|
|
251
|
+
__asm__(
|
|
252
|
+
".text\n\t"
|
|
253
|
+
".globl ffi_trampoline\n\t"
|
|
254
|
+
".globl _ffi_trampoline\n\t"
|
|
255
|
+
"ffi_trampoline:\n\t"
|
|
256
|
+
"_ffi_trampoline:\n\t"
|
|
257
|
+
"subl $12, %esp\n\t"
|
|
258
|
+
"leal 16(%esp), %eax\n\t"
|
|
259
|
+
"movl %eax, (%esp)\n\t"
|
|
260
|
+
"movl $0xfee1dead, 4(%esp)\n\t"
|
|
261
|
+
"movl $0xbeefcafe, %eax\n\t"
|
|
262
|
+
"call *%eax\n\t"
|
|
263
|
+
"addl $12, %esp\n\t"
|
|
264
|
+
"ret\n\t"
|
|
265
|
+
".globl ffi_trampoline_end\n\t"
|
|
266
|
+
"ffi_trampoline_end:\n\t"
|
|
267
|
+
".globl _ffi_trampoline_end\n\t"
|
|
268
|
+
"_ffi_trampoline_end:\n\t"
|
|
269
|
+
);
|
|
270
|
+
|
|
271
|
+
static VALUE
|
|
272
|
+
custom_trampoline(caddr_t args, Closure* handle)
|
|
273
|
+
{
|
|
274
|
+
FunctionType* fnInfo = (FunctionType *) handle->info;
|
|
275
|
+
return (*fnInfo->invoke)(*(int *) args, *(VALUE **) (args + 4), handle->function, fnInfo);
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
#endif /* __x86_64__ else __i386__ */
|
|
279
|
+
|
|
280
|
+
extern void ffi_trampoline(int argc, VALUE* argv, VALUE self);
|
|
281
|
+
extern void ffi_trampoline_end(void);
|
|
282
|
+
static int trampoline_offsets(long *, long *);
|
|
283
|
+
|
|
284
|
+
static long trampoline_ctx_offset, trampoline_func_offset;
|
|
285
|
+
|
|
286
|
+
static long
|
|
287
|
+
trampoline_offset(int off, const long value)
|
|
288
|
+
{
|
|
289
|
+
caddr_t ptr;
|
|
290
|
+
for (ptr = (caddr_t) &ffi_trampoline + off; ptr < (caddr_t) &ffi_trampoline_end; ++ptr) {
|
|
291
|
+
if (*(long *) ptr == value) {
|
|
292
|
+
return ptr - (caddr_t) &ffi_trampoline;
|
|
293
|
+
}
|
|
79
294
|
}
|
|
80
|
-
closure->info = fnInfo;
|
|
81
|
-
closure->function = function;
|
|
82
295
|
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
296
|
+
return -1;
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
static int
|
|
300
|
+
trampoline_offsets(long* ctxOffset, long* fnOffset)
|
|
301
|
+
{
|
|
302
|
+
*ctxOffset = trampoline_offset(0, TRAMPOLINE_CTX_MAGIC);
|
|
303
|
+
if (*ctxOffset == -1) {
|
|
304
|
+
return -1;
|
|
91
305
|
}
|
|
92
306
|
|
|
93
|
-
|
|
94
|
-
|
|
307
|
+
*fnOffset = trampoline_offset(0, TRAMPOLINE_FUN_MAGIC);
|
|
308
|
+
if (*fnOffset == -1) {
|
|
309
|
+
return -1;
|
|
310
|
+
}
|
|
95
311
|
|
|
96
|
-
return
|
|
312
|
+
return 0;
|
|
97
313
|
}
|
|
98
314
|
|
|
99
|
-
|
|
100
|
-
|
|
315
|
+
static bool
|
|
316
|
+
prep_trampoline(void* ctx, void* code, Closure* closure, char* errmsg, size_t errmsgsize)
|
|
101
317
|
{
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
318
|
+
caddr_t ptr = (caddr_t) code;
|
|
319
|
+
|
|
320
|
+
memcpy(ptr, &ffi_trampoline, trampoline_size());
|
|
321
|
+
/* Patch the context and function addresses into the stub code */
|
|
322
|
+
*(intptr_t *)(ptr + trampoline_ctx_offset) = (intptr_t) closure;
|
|
323
|
+
*(intptr_t *)(ptr + trampoline_func_offset) = (intptr_t) custom_trampoline;
|
|
324
|
+
|
|
325
|
+
return true;
|
|
105
326
|
}
|
|
106
327
|
|
|
107
|
-
|
|
108
|
-
|
|
328
|
+
static long
|
|
329
|
+
trampoline_size(void)
|
|
109
330
|
{
|
|
110
|
-
return
|
|
331
|
+
return (caddr_t) &ffi_trampoline_end - (caddr_t) &ffi_trampoline;
|
|
111
332
|
}
|
|
112
333
|
|
|
334
|
+
#endif /* CUSTOM_TRAMPOLINE */
|
|
335
|
+
|
|
336
|
+
|
|
113
337
|
void
|
|
114
338
|
rbffi_MethodHandle_Init(VALUE module)
|
|
115
339
|
{
|
|
340
|
+
#ifndef CUSTOM_TRAMPOLINE
|
|
116
341
|
ffi_status ffiStatus;
|
|
342
|
+
#endif
|
|
117
343
|
|
|
344
|
+
defaultClosurePool = rbffi_ClosurePool_New((int) trampoline_size(), prep_trampoline, NULL);
|
|
345
|
+
|
|
346
|
+
#if defined(CUSTOM_TRAMPOLINE)
|
|
347
|
+
if (trampoline_offsets(&trampoline_ctx_offset, &trampoline_func_offset) != 0) {
|
|
348
|
+
rb_raise(rb_eFatal, "Could not locate offsets in trampoline code");
|
|
349
|
+
}
|
|
350
|
+
#else
|
|
118
351
|
ffiStatus = ffi_prep_cif(&mh_cif, FFI_DEFAULT_ABI, 3, &ffi_type_ulong,
|
|
119
352
|
methodHandleParamTypes);
|
|
120
353
|
if (ffiStatus != FFI_OK) {
|
|
121
354
|
rb_raise(rb_eFatal, "ffi_prep_cif failed. status=%#x", ffiStatus);
|
|
122
355
|
}
|
|
356
|
+
|
|
357
|
+
#endif
|
|
123
358
|
}
|
data/ext/ffi_c/ffi.c
CHANGED
|
@@ -46,7 +46,7 @@
|
|
|
46
46
|
#include "Types.h"
|
|
47
47
|
#include "LastError.h"
|
|
48
48
|
#include "Function.h"
|
|
49
|
-
#include "
|
|
49
|
+
#include "ClosurePool.h"
|
|
50
50
|
#include "MethodHandle.h"
|
|
51
51
|
#include "Call.h"
|
|
52
52
|
#include "ArrayType.h"
|
|
@@ -79,7 +79,7 @@ Init_ffi_c(void)
|
|
|
79
79
|
rbffi_ArrayType_Init(moduleFFI);
|
|
80
80
|
rbffi_LastError_Init(moduleFFI);
|
|
81
81
|
rbffi_Call_Init(moduleFFI);
|
|
82
|
-
|
|
82
|
+
rbffi_ClosurePool_Init(moduleFFI);
|
|
83
83
|
rbffi_MethodHandle_Init(moduleFFI);
|
|
84
84
|
rbffi_Platform_Init(moduleFFI);
|
|
85
85
|
rbffi_AbstractMemory_Init(moduleFFI);
|
data/lib/ffi/version.rb
CHANGED
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: ffi
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 1.9.
|
|
4
|
+
version: 1.9.25
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Wayne Meissner
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2018-06-
|
|
11
|
+
date: 2018-06-03 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: rake
|
|
@@ -106,8 +106,8 @@ files:
|
|
|
106
106
|
- ext/ffi_c/Buffer.c
|
|
107
107
|
- ext/ffi_c/Call.c
|
|
108
108
|
- ext/ffi_c/Call.h
|
|
109
|
-
- ext/ffi_c/
|
|
110
|
-
- ext/ffi_c/
|
|
109
|
+
- ext/ffi_c/ClosurePool.c
|
|
110
|
+
- ext/ffi_c/ClosurePool.h
|
|
111
111
|
- ext/ffi_c/DataConverter.c
|
|
112
112
|
- ext/ffi_c/DynamicLibrary.c
|
|
113
113
|
- ext/ffi_c/DynamicLibrary.h
|
data/ext/ffi_c/Closure.c
DELETED
|
@@ -1,54 +0,0 @@
|
|
|
1
|
-
/*
|
|
2
|
-
* Copyright (c) 2009, 2010 Wayne Meissner
|
|
3
|
-
* Copyright (c) 2008-2016, Ruby FFI project contributors
|
|
4
|
-
* All rights reserved.
|
|
5
|
-
*
|
|
6
|
-
* Redistribution and use in source and binary forms, with or without
|
|
7
|
-
* modification, are permitted provided that the following conditions are met:
|
|
8
|
-
* * Redistributions of source code must retain the above copyright
|
|
9
|
-
* notice, this list of conditions and the following disclaimer.
|
|
10
|
-
* * Redistributions in binary form must reproduce the above copyright
|
|
11
|
-
* notice, this list of conditions and the following disclaimer in the
|
|
12
|
-
* documentation and/or other materials provided with the distribution.
|
|
13
|
-
* * Neither the name of the Ruby FFI project nor the
|
|
14
|
-
* names of its contributors may be used to endorse or promote products
|
|
15
|
-
* derived from this software without specific prior written permission.
|
|
16
|
-
*
|
|
17
|
-
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
|
18
|
-
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
|
19
|
-
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
20
|
-
* DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
|
|
21
|
-
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
|
22
|
-
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
|
23
|
-
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
|
24
|
-
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
25
|
-
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
|
26
|
-
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
27
|
-
*/
|
|
28
|
-
|
|
29
|
-
#include <ffi.h>
|
|
30
|
-
#include "Closure.h"
|
|
31
|
-
#include "rbffi.h"
|
|
32
|
-
|
|
33
|
-
Closure* rbffi_Closure_Alloc(void)
|
|
34
|
-
{
|
|
35
|
-
Closure *self;
|
|
36
|
-
|
|
37
|
-
self = xmalloc(sizeof(Closure));
|
|
38
|
-
self->libffi_closure = ffi_closure_alloc(sizeof(ffi_closure), &self->libffi_trampoline);
|
|
39
|
-
if (!self->libffi_closure) {
|
|
40
|
-
return NULL;
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
return self;
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
void rbffi_Closure_Free(Closure *self)
|
|
47
|
-
{
|
|
48
|
-
ffi_closure_free(self->libffi_closure);
|
|
49
|
-
free(self);
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
void rbffi_Closure_Init(VALUE moduleFFI)
|
|
53
|
-
{
|
|
54
|
-
}
|