ffi 0.4.0 → 0.5.0
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of ffi might be problematic. Click here for more details.
- data/README.rdoc +15 -15
- data/Rakefile +57 -8
- data/ext/ffi_c/AbstractMemory.c +101 -24
- data/ext/ffi_c/AbstractMemory.h +98 -6
- data/ext/ffi_c/ArrayType.c +129 -0
- data/ext/ffi_c/ArrayType.h +58 -0
- data/ext/ffi_c/AutoPointer.c +1 -0
- data/ext/ffi_c/Buffer.c +59 -43
- data/ext/ffi_c/Call.c +853 -0
- data/ext/ffi_c/Call.h +86 -0
- data/ext/ffi_c/ClosurePool.c +302 -0
- data/ext/ffi_c/ClosurePool.h +29 -0
- data/ext/ffi_c/DynamicLibrary.c +3 -0
- data/ext/ffi_c/Function.c +478 -0
- data/ext/ffi_c/Function.h +80 -0
- data/ext/ffi_c/FunctionInfo.c +221 -0
- data/ext/ffi_c/LastError.c +30 -6
- data/ext/ffi_c/MemoryPointer.c +50 -28
- data/ext/ffi_c/MethodHandle.c +346 -0
- data/ext/ffi_c/MethodHandle.h +53 -0
- data/ext/ffi_c/Pointer.c +73 -13
- data/ext/ffi_c/Pointer.h +31 -7
- data/ext/ffi_c/Struct.c +517 -224
- data/ext/ffi_c/Struct.h +60 -6
- data/ext/ffi_c/StructByValue.c +140 -0
- data/ext/ffi_c/StructByValue.h +53 -0
- data/ext/ffi_c/StructLayout.c +450 -0
- data/ext/ffi_c/Type.c +121 -22
- data/ext/ffi_c/Type.h +37 -8
- data/ext/ffi_c/Types.c +46 -61
- data/ext/ffi_c/Types.h +38 -7
- data/ext/ffi_c/Variadic.c +260 -0
- data/ext/ffi_c/compat.h +53 -3
- data/ext/ffi_c/extconf.rb +6 -7
- data/ext/ffi_c/ffi.c +45 -39
- data/ext/ffi_c/libffi.darwin.mk +2 -2
- data/ext/ffi_c/rbffi.h +3 -0
- data/lib/ffi/ffi.rb +7 -4
- data/lib/ffi/library.rb +34 -59
- data/lib/ffi/platform.rb +14 -4
- data/lib/ffi/struct.rb +110 -281
- data/lib/ffi/union.rb +4 -9
- data/lib/ffi/variadic.rb +1 -6
- data/spec/ffi/buffer_spec.rb +6 -0
- data/spec/ffi/callback_spec.rb +34 -3
- data/spec/ffi/function_spec.rb +73 -0
- data/spec/ffi/library_spec.rb +56 -52
- data/spec/ffi/pointer_spec.rb +3 -3
- data/spec/ffi/struct_callback_spec.rb +26 -3
- data/spec/ffi/struct_spec.rb +56 -3
- metadata +42 -11
- data/ext/ffi_c/Callback.c +0 -374
- data/ext/ffi_c/Callback.h +0 -47
- data/ext/ffi_c/Invoker.c +0 -962
- data/ext/ffi_c/NullPointer.c +0 -143
data/ext/ffi_c/Callback.h
DELETED
@@ -1,47 +0,0 @@
|
|
1
|
-
#ifndef _CALLBACK_H
|
2
|
-
#define _CALLBACK_H
|
3
|
-
|
4
|
-
#include "Types.h"
|
5
|
-
#include "Type.h"
|
6
|
-
|
7
|
-
#ifdef __cplusplus
|
8
|
-
extern "C" {
|
9
|
-
#endif
|
10
|
-
#include <ffi.h>
|
11
|
-
|
12
|
-
typedef struct {
|
13
|
-
Type type; // The native type of a CallbackInfo object
|
14
|
-
VALUE rbReturnType;
|
15
|
-
VALUE rbParameterTypes;
|
16
|
-
|
17
|
-
Type* returnType;
|
18
|
-
Type** parameterTypes;
|
19
|
-
ffi_type* ffiReturnType;
|
20
|
-
ffi_type** ffiParameterTypes;
|
21
|
-
ffi_cif ffi_cif;
|
22
|
-
int parameterCount;
|
23
|
-
int flags;
|
24
|
-
ffi_abi abi;
|
25
|
-
} CallbackInfo;
|
26
|
-
|
27
|
-
typedef struct {
|
28
|
-
void* code;
|
29
|
-
ffi_closure* ffi_closure;
|
30
|
-
ffi_cif ffi_cif;
|
31
|
-
int flags;
|
32
|
-
CallbackInfo* cbInfo;
|
33
|
-
VALUE rbCallbackInfo;
|
34
|
-
VALUE rbProc;
|
35
|
-
} NativeCallback;
|
36
|
-
|
37
|
-
extern VALUE rbffi_CallbackInfoClass;
|
38
|
-
extern void rbffi_Callback_Init(VALUE ffiModule);
|
39
|
-
extern VALUE rbffi_NativeCallback_NewInstance(VALUE, VALUE);
|
40
|
-
extern VALUE rbffi_NativeCallback_ForProc(VALUE proc, VALUE cbInfo);
|
41
|
-
|
42
|
-
#ifdef __cplusplus
|
43
|
-
}
|
44
|
-
#endif
|
45
|
-
|
46
|
-
#endif /* _CALLBACK_H */
|
47
|
-
|
data/ext/ffi_c/Invoker.c
DELETED
@@ -1,962 +0,0 @@
|
|
1
|
-
#include <sys/param.h>
|
2
|
-
#include <sys/types.h>
|
3
|
-
#ifndef _WIN32
|
4
|
-
# include <sys/mman.h>
|
5
|
-
#endif
|
6
|
-
#include <stdio.h>
|
7
|
-
#include <stdint.h>
|
8
|
-
#include <stdbool.h>
|
9
|
-
#ifndef _WIN32
|
10
|
-
# include <unistd.h>
|
11
|
-
# include <pthread.h>
|
12
|
-
#endif
|
13
|
-
#include <errno.h>
|
14
|
-
#include <ruby.h>
|
15
|
-
|
16
|
-
#include <ffi.h>
|
17
|
-
#include "rbffi.h"
|
18
|
-
#include "compat.h"
|
19
|
-
|
20
|
-
#include "AbstractMemory.h"
|
21
|
-
#include "Pointer.h"
|
22
|
-
#include "Struct.h"
|
23
|
-
#include "Platform.h"
|
24
|
-
#include "Callback.h"
|
25
|
-
#include "Types.h"
|
26
|
-
#include "Type.h"
|
27
|
-
#include "LastError.h"
|
28
|
-
|
29
|
-
#if defined(__i386__) && !defined(_WIN32) && !defined(__WIN32__)
|
30
|
-
# define USE_RAW
|
31
|
-
#endif
|
32
|
-
#if defined(HAVE_NATIVETHREAD) && !defined(_WIN32) && !defined(__WIN32__)
|
33
|
-
# define USE_PTHREAD_LOCAL
|
34
|
-
#endif
|
35
|
-
#define MAX_FIXED_ARITY (3)
|
36
|
-
|
37
|
-
#ifndef roundup
|
38
|
-
# define roundup(x, y) ((((x)+((y)-1))/(y))*(y))
|
39
|
-
#endif
|
40
|
-
|
41
|
-
typedef struct MethodHandle MethodHandle;
|
42
|
-
typedef struct Invoker Invoker;
|
43
|
-
|
44
|
-
struct Invoker {
|
45
|
-
VALUE address;
|
46
|
-
VALUE enums;
|
47
|
-
void* function;
|
48
|
-
ffi_cif cif;
|
49
|
-
int paramCount;
|
50
|
-
ffi_type** ffiParamTypes;
|
51
|
-
NativeType* paramTypes;
|
52
|
-
Type* returnType;
|
53
|
-
VALUE rbReturnType;
|
54
|
-
VALUE callbackArray;
|
55
|
-
int callbackCount;
|
56
|
-
VALUE* callbackParameters;
|
57
|
-
ffi_abi abi;
|
58
|
-
MethodHandle* methodHandle;
|
59
|
-
};
|
60
|
-
#ifdef USE_RAW
|
61
|
-
# define METHOD_CLOSURE ffi_raw_closure
|
62
|
-
#else
|
63
|
-
# define METHOD_CLOSURE ffi_closure
|
64
|
-
#endif
|
65
|
-
typedef struct MethodHandlePool MethodHandlePool;
|
66
|
-
struct MethodHandle {
|
67
|
-
Invoker* invoker;
|
68
|
-
int arity;
|
69
|
-
METHOD_CLOSURE* closure;
|
70
|
-
void* code;
|
71
|
-
ffi_cif cif;
|
72
|
-
struct MethodHandlePool* pool;
|
73
|
-
MethodHandle* next;
|
74
|
-
};
|
75
|
-
#if !defined(_WIN32) && !defined(__WIN32__)
|
76
|
-
struct MethodHandlePool {
|
77
|
-
#ifdef HAVE_NATIVETHREAD
|
78
|
-
pthread_mutex_t mutex;
|
79
|
-
#endif
|
80
|
-
MethodHandle* list;
|
81
|
-
};
|
82
|
-
#endif /* _WIN32 */
|
83
|
-
|
84
|
-
static VALUE invoker_allocate(VALUE klass);
|
85
|
-
static VALUE invoker_initialize(VALUE self, VALUE function, VALUE parameterTypes,
|
86
|
-
VALUE rbReturnType, VALUE returnType, VALUE convention, VALUE enums);
|
87
|
-
static void invoker_mark(Invoker *);
|
88
|
-
static void invoker_free(Invoker *);
|
89
|
-
static VALUE invoker_call(int argc, VALUE* argv, VALUE self);
|
90
|
-
static VALUE invoker_arity(VALUE self);
|
91
|
-
static void* callback_param(VALUE proc, VALUE cbinfo);
|
92
|
-
#ifdef USE_RAW
|
93
|
-
static void attached_method_invoke(ffi_cif* cif, void* retval, ffi_raw* parameters, void* user_data);
|
94
|
-
static void attached_method_vinvoke(ffi_cif* cif, void* retval, ffi_raw* parameters, void* user_data);
|
95
|
-
#else
|
96
|
-
#ifndef _WIN32
|
97
|
-
static void attached_method_invoke(ffi_cif* cif, void* retval, void** parameters, void* user_data);
|
98
|
-
#endif /* _WIN32 */
|
99
|
-
static void attached_method_vinvoke(ffi_cif* cif, void* retval, void** parameters, void* user_data);
|
100
|
-
#endif
|
101
|
-
static MethodHandle* method_handle_alloc(int arity);
|
102
|
-
static void method_handle_free(MethodHandle *);
|
103
|
-
|
104
|
-
|
105
|
-
#ifndef _WIN32
|
106
|
-
static int PageSize;
|
107
|
-
#endif
|
108
|
-
|
109
|
-
VALUE rbffi_InvokerClass = Qnil;
|
110
|
-
static VALUE classInvoker = Qnil, classVariadicInvoker = Qnil;
|
111
|
-
static ID to_ptr = 0;
|
112
|
-
static ID map_symbol_id = 0;
|
113
|
-
|
114
|
-
#ifdef USE_RAW
|
115
|
-
# ifndef __i386__
|
116
|
-
# error "RAW argument packing only supported on i386"
|
117
|
-
# endif
|
118
|
-
|
119
|
-
#define INT8_SIZE (sizeof(char))
|
120
|
-
#define INT16_SIZE (sizeof(short))
|
121
|
-
#define INT32_SIZE (sizeof(int))
|
122
|
-
#define INT64_SIZE (sizeof(long long))
|
123
|
-
#define FLOAT32_SIZE (sizeof(float))
|
124
|
-
#define FLOAT64_SIZE (sizeof(double))
|
125
|
-
#define ADDRESS_SIZE (sizeof(void *))
|
126
|
-
#define INT8_ADJ (4)
|
127
|
-
#define INT16_ADJ (4)
|
128
|
-
#define INT32_ADJ (4)
|
129
|
-
#define INT64_ADJ (8)
|
130
|
-
#define FLOAT32_ADJ (4)
|
131
|
-
#define FLOAT64_ADJ (8)
|
132
|
-
#define ADDRESS_ADJ (sizeof(void *))
|
133
|
-
|
134
|
-
#endif /* USE_RAW */
|
135
|
-
|
136
|
-
#ifdef USE_RAW
|
137
|
-
# define ADJ(p, a) ((p) = (FFIStorage*) (((char *) p) + a##_ADJ))
|
138
|
-
#else
|
139
|
-
# define ADJ(p, a) (++(p))
|
140
|
-
#endif
|
141
|
-
|
142
|
-
static VALUE
|
143
|
-
invoker_allocate(VALUE klass)
|
144
|
-
{
|
145
|
-
Invoker *invoker;
|
146
|
-
VALUE obj = Data_Make_Struct(klass, Invoker, invoker_mark, invoker_free, invoker);
|
147
|
-
|
148
|
-
invoker->rbReturnType = Qnil;
|
149
|
-
invoker->callbackArray = Qnil;
|
150
|
-
invoker->address = Qnil;
|
151
|
-
invoker->enums = Qnil;
|
152
|
-
|
153
|
-
return obj;
|
154
|
-
}
|
155
|
-
|
156
|
-
static VALUE
|
157
|
-
invoker_initialize(VALUE self, VALUE function, VALUE parameterTypes,
|
158
|
-
VALUE rbReturnTypeSymbol, VALUE returnType, VALUE convention, VALUE enums)
|
159
|
-
{
|
160
|
-
Invoker* invoker = NULL;
|
161
|
-
ffi_type* ffiReturnType;
|
162
|
-
ffi_abi abi;
|
163
|
-
ffi_status ffiStatus;
|
164
|
-
int i;
|
165
|
-
|
166
|
-
Check_Type(parameterTypes, T_ARRAY);
|
167
|
-
Check_Type(rbReturnTypeSymbol, T_SYMBOL);
|
168
|
-
Check_Type(convention, T_STRING);
|
169
|
-
Check_Type(function, T_DATA);
|
170
|
-
|
171
|
-
Data_Get_Struct(self, Invoker, invoker);
|
172
|
-
invoker->enums = enums;
|
173
|
-
invoker->address = function;
|
174
|
-
invoker->function = rbffi_AbstractMemory_Cast(function, rbffi_PointerClass)->address;
|
175
|
-
invoker->paramCount = RARRAY_LEN(parameterTypes);
|
176
|
-
invoker->paramTypes = ALLOC_N(NativeType, invoker->paramCount);
|
177
|
-
invoker->ffiParamTypes = ALLOC_N(ffi_type *, invoker->paramCount);
|
178
|
-
|
179
|
-
for (i = 0; i < invoker->paramCount; ++i) {
|
180
|
-
VALUE entry = rb_ary_entry(parameterTypes, i);
|
181
|
-
if (rb_obj_is_kind_of(entry, rbffi_CallbackInfoClass)) {
|
182
|
-
invoker->callbackParameters = REALLOC_N(invoker->callbackParameters, VALUE,
|
183
|
-
invoker->callbackCount + 1);
|
184
|
-
invoker->callbackParameters[invoker->callbackCount++] = entry;
|
185
|
-
invoker->paramTypes[i] = NATIVE_CALLBACK;
|
186
|
-
invoker->ffiParamTypes[i] = &ffi_type_pointer;
|
187
|
-
} else if (rb_obj_is_kind_of(entry, rbffi_TypeClass)){
|
188
|
-
int paramType = rbffi_Type_GetIntValue(entry);
|
189
|
-
invoker->paramTypes[i] = paramType;
|
190
|
-
invoker->ffiParamTypes[i] = rbffi_NativeType_ToFFI(paramType);
|
191
|
-
}
|
192
|
-
if (invoker->ffiParamTypes[i] == NULL) {
|
193
|
-
rb_raise(rb_eTypeError, "Invalid parameter type");
|
194
|
-
}
|
195
|
-
}
|
196
|
-
if (!rb_obj_is_kind_of(returnType, rbffi_TypeClass)) {
|
197
|
-
rb_raise(rb_eTypeError, "Invalid return type");
|
198
|
-
}
|
199
|
-
Data_Get_Struct(returnType, Type, invoker->returnType);
|
200
|
-
invoker->rbReturnType = rb_obj_is_kind_of(returnType, rbffi_CallbackInfoClass)
|
201
|
-
? returnType : rbReturnTypeSymbol;
|
202
|
-
|
203
|
-
ffiReturnType = invoker->returnType->ffiType;
|
204
|
-
if (ffiReturnType == NULL) {
|
205
|
-
rb_raise(rb_eTypeError, "Invalid return type");
|
206
|
-
}
|
207
|
-
#if defined(_WIN32) || defined(__WIN32__)
|
208
|
-
abi = strcmp(StringValueCStr(convention), "stdcall") == 0 ? FFI_STDCALL : FFI_DEFAULT_ABI;
|
209
|
-
#else
|
210
|
-
abi = FFI_DEFAULT_ABI;
|
211
|
-
#endif
|
212
|
-
ffiStatus = ffi_prep_cif(&invoker->cif, abi, invoker->paramCount,
|
213
|
-
ffiReturnType, invoker->ffiParamTypes);
|
214
|
-
switch (ffiStatus) {
|
215
|
-
case FFI_BAD_ABI:
|
216
|
-
rb_raise(rb_eArgError, "Invalid ABI specified");
|
217
|
-
case FFI_BAD_TYPEDEF:
|
218
|
-
rb_raise(rb_eArgError, "Invalid argument type specified");
|
219
|
-
case FFI_OK:
|
220
|
-
break;
|
221
|
-
default:
|
222
|
-
rb_raise(rb_eArgError, "Unknown FFI error");
|
223
|
-
}
|
224
|
-
invoker->methodHandle = method_handle_alloc(invoker->callbackCount < 1 ? invoker->paramCount : -1);
|
225
|
-
invoker->methodHandle->invoker = invoker;
|
226
|
-
return self;
|
227
|
-
}
|
228
|
-
|
229
|
-
static VALUE
|
230
|
-
variadic_invoker_new(VALUE klass, VALUE function, VALUE rbReturnTypeSymbol, VALUE returnType, VALUE convention, VALUE enums)
|
231
|
-
{
|
232
|
-
Invoker* invoker = NULL;
|
233
|
-
VALUE retval = Qnil;
|
234
|
-
|
235
|
-
Check_Type(rbReturnTypeSymbol, T_SYMBOL);
|
236
|
-
Check_Type(convention, T_STRING);
|
237
|
-
Check_Type(function, T_DATA);
|
238
|
-
|
239
|
-
retval = Data_Make_Struct(klass, Invoker, invoker_mark, invoker_free, invoker);
|
240
|
-
invoker->enums = enums;
|
241
|
-
invoker->address = function;
|
242
|
-
invoker->function = rbffi_AbstractMemory_Cast(function, rbffi_PointerClass)->address;
|
243
|
-
#if defined(_WIN32) || defined(__WIN32__)
|
244
|
-
invoker->abi = strcmp(StringValueCStr(convention), "stdcall") == 0 ? FFI_STDCALL : FFI_DEFAULT_ABI;
|
245
|
-
#else
|
246
|
-
invoker->abi = FFI_DEFAULT_ABI;
|
247
|
-
#endif
|
248
|
-
|
249
|
-
invoker->rbReturnType = rb_obj_is_kind_of(returnType, rbffi_CallbackInfoClass)
|
250
|
-
? returnType : rbReturnTypeSymbol;
|
251
|
-
if (!rb_obj_is_kind_of(returnType, rbffi_TypeClass)) {
|
252
|
-
rb_raise(rb_eTypeError, "Invalid return type");
|
253
|
-
}
|
254
|
-
Data_Get_Struct(returnType, Type, invoker->returnType);
|
255
|
-
invoker->paramCount = -1;
|
256
|
-
return retval;
|
257
|
-
}
|
258
|
-
|
259
|
-
static ffi_type* methodHandleParamTypes[MAX_FIXED_ARITY + 2];
|
260
|
-
static ffi_type* methodHandleVarargParamTypes[]= {
|
261
|
-
&ffi_type_sint,
|
262
|
-
&ffi_type_pointer,
|
263
|
-
NULL,
|
264
|
-
};
|
265
|
-
|
266
|
-
#if defined(_WIN32) || defined(__WIN32__)
|
267
|
-
static MethodHandle*
|
268
|
-
method_handle_alloc(int arity)
|
269
|
-
{
|
270
|
-
char errmsg[1024];
|
271
|
-
ffi_type* ffiReturnType = (sizeof (VALUE) == sizeof (long))
|
272
|
-
? &ffi_type_ulong : &ffi_type_uint64;
|
273
|
-
int ffiParamCount, ffiStatus;
|
274
|
-
MethodHandle* method = NULL;
|
275
|
-
ffi_type** ffiParamTypes;
|
276
|
-
void (*fn)(ffi_cif* cif, void* retval, void** parameters, void* user_data);
|
277
|
-
|
278
|
-
ffiParamCount = 3;
|
279
|
-
ffiParamTypes = methodHandleVarargParamTypes;
|
280
|
-
fn = attached_method_vinvoke;
|
281
|
-
method = ALLOC_N(MethodHandle, 1);
|
282
|
-
memset(method, 0, sizeof(*method));
|
283
|
-
method->arity = -1;
|
284
|
-
ffiStatus = ffi_prep_cif(&method->cif, FFI_DEFAULT_ABI, ffiParamCount,
|
285
|
-
ffiReturnType, ffiParamTypes);
|
286
|
-
if (ffiStatus != FFI_OK) {
|
287
|
-
snprintf(errmsg, sizeof (errmsg), "ffi_prep_cif failed. status=%#x", ffiStatus);
|
288
|
-
goto error;
|
289
|
-
}
|
290
|
-
method->closure = ffi_closure_alloc(sizeof(*method->closure), &method->code);
|
291
|
-
if (method->closure == NULL) {
|
292
|
-
snprintf(errmsg, sizeof(errmsg), "ffi_closure_alloc failed");
|
293
|
-
goto error;
|
294
|
-
}
|
295
|
-
ffiStatus = ffi_prep_closure_loc(method->closure, &method->cif, fn, method, method->code);
|
296
|
-
if (ffiStatus != FFI_OK) {
|
297
|
-
snprintf(errmsg, sizeof (errmsg), "ffi_prep_closure failed. status=%#x", ffiStatus);
|
298
|
-
goto error;
|
299
|
-
}
|
300
|
-
return method;
|
301
|
-
error:
|
302
|
-
if (method != NULL) {
|
303
|
-
if (method->closure != NULL) {
|
304
|
-
ffi_closure_free(method->closure);
|
305
|
-
}
|
306
|
-
xfree(method);
|
307
|
-
}
|
308
|
-
rb_raise(rb_eRuntimeError, "%s", errmsg);
|
309
|
-
}
|
310
|
-
static void
|
311
|
-
method_handle_free(MethodHandle* method)
|
312
|
-
{
|
313
|
-
if (method->closure != NULL) {
|
314
|
-
ffi_closure_free(method->closure);
|
315
|
-
}
|
316
|
-
xfree(method);
|
317
|
-
}
|
318
|
-
#else
|
319
|
-
static MethodHandlePool methodHandlePool[MAX_FIXED_ARITY + 1], defaultMethodHandlePool;
|
320
|
-
|
321
|
-
#if defined(HAVE_NATIVETHREAD) && !defined(_WIN32)
|
322
|
-
# define pool_lock(p) pthread_mutex_lock(&(p)->mutex)
|
323
|
-
# define pool_unlock(p) pthread_mutex_unlock(&(p)->mutex)
|
324
|
-
#else
|
325
|
-
# define pool_lock(p)
|
326
|
-
# define pool_unlock(p)
|
327
|
-
#endif
|
328
|
-
static MethodHandle*
|
329
|
-
method_handle_alloc(int arity)
|
330
|
-
{
|
331
|
-
MethodHandle* method, *list = NULL;
|
332
|
-
MethodHandlePool* pool;
|
333
|
-
ffi_type** ffiParamTypes;
|
334
|
-
ffi_type* ffiReturnType;
|
335
|
-
caddr_t page;
|
336
|
-
int ffiParamCount, ffiStatus;
|
337
|
-
int nclosures, closureSize, methodArity;
|
338
|
-
int i;
|
339
|
-
#ifdef USE_RAW
|
340
|
-
void (*fn)(ffi_cif* cif, void* retval, ffi_raw* parameters, void* user_data);
|
341
|
-
#else
|
342
|
-
void (*fn)(ffi_cif* cif, void* retval, void** parameters, void* user_data);
|
343
|
-
#endif
|
344
|
-
|
345
|
-
|
346
|
-
pool = (arity >= 0 && arity <= MAX_FIXED_ARITY) ? &methodHandlePool[arity] : &defaultMethodHandlePool;
|
347
|
-
pool_lock(pool);
|
348
|
-
if (pool->list != NULL) {
|
349
|
-
method = pool->list;
|
350
|
-
pool->list = pool->list->next;
|
351
|
-
pool_unlock(pool);
|
352
|
-
return method;
|
353
|
-
}
|
354
|
-
ffiReturnType = (sizeof (VALUE) == sizeof (long))
|
355
|
-
? &ffi_type_ulong : &ffi_type_uint64;
|
356
|
-
closureSize = roundup(sizeof(METHOD_CLOSURE), 8);
|
357
|
-
nclosures = PageSize / closureSize;
|
358
|
-
page = mmap(NULL, PageSize, PROT_READ | PROT_WRITE, MAP_ANON | MAP_PRIVATE, -1, 0);
|
359
|
-
if (page == (caddr_t) -1) {
|
360
|
-
pool_unlock(pool);
|
361
|
-
rb_raise(rb_eRuntimeError, "mmap failed. errno=%d (%s)", errno, strerror(errno));
|
362
|
-
}
|
363
|
-
|
364
|
-
/* figure out whichh function to bounce the execution through */
|
365
|
-
if (arity >= 0 && arity <= MAX_FIXED_ARITY) {
|
366
|
-
ffiParamCount = arity + 1;
|
367
|
-
ffiParamTypes = methodHandleParamTypes;
|
368
|
-
fn = attached_method_invoke;
|
369
|
-
methodArity = arity;
|
370
|
-
} else {
|
371
|
-
ffiParamCount = 3;
|
372
|
-
ffiParamTypes = methodHandleVarargParamTypes;
|
373
|
-
fn = attached_method_vinvoke;
|
374
|
-
methodArity = -1;
|
375
|
-
}
|
376
|
-
|
377
|
-
for (i = 0; i < nclosures; ++i) {
|
378
|
-
char errmsg[256];
|
379
|
-
method = calloc(1, sizeof(MethodHandle));
|
380
|
-
if (method == NULL) {
|
381
|
-
snprintf(errmsg, sizeof(errmsg), "malloc failed: %s", strerror(errno));
|
382
|
-
goto error;
|
383
|
-
}
|
384
|
-
method->next = list;
|
385
|
-
list = method;
|
386
|
-
method->pool = pool;
|
387
|
-
method->code = method->closure = (METHOD_CLOSURE *) (page + (i * closureSize));
|
388
|
-
|
389
|
-
ffiStatus = ffi_prep_cif(&method->cif, FFI_DEFAULT_ABI, ffiParamCount,
|
390
|
-
ffiReturnType, ffiParamTypes);
|
391
|
-
if (ffiStatus != FFI_OK) {
|
392
|
-
snprintf(errmsg, sizeof(errmsg), "ffi_prep_cif failed. status=%#x", ffiStatus);
|
393
|
-
goto error;
|
394
|
-
}
|
395
|
-
|
396
|
-
#ifdef USE_RAW
|
397
|
-
ffiStatus = ffi_prep_raw_closure(method->closure, &method->cif, fn, method);
|
398
|
-
#else
|
399
|
-
ffiStatus = ffi_prep_closure(method->closure, &method->cif, fn, method);
|
400
|
-
#endif
|
401
|
-
if (ffiStatus != FFI_OK) {
|
402
|
-
snprintf(errmsg, sizeof(errmsg), "ffi_prep_closure failed. status=%#x", ffiStatus);
|
403
|
-
goto error;
|
404
|
-
}
|
405
|
-
method->arity = methodArity;
|
406
|
-
continue;
|
407
|
-
error:
|
408
|
-
while (list != NULL) {
|
409
|
-
method = list;
|
410
|
-
list = list->next;
|
411
|
-
free(method);
|
412
|
-
}
|
413
|
-
munmap(page, PageSize);
|
414
|
-
pool_unlock(pool);
|
415
|
-
rb_raise(rb_eRuntimeError, "%s", errmsg);
|
416
|
-
}
|
417
|
-
mprotect(page, PageSize, PROT_READ | PROT_EXEC);
|
418
|
-
|
419
|
-
/* take the first member of the list for this handle */
|
420
|
-
method = list;
|
421
|
-
list = list->next;
|
422
|
-
|
423
|
-
/* now add the new block of MethodHandles to the pool */
|
424
|
-
if (list != NULL) {
|
425
|
-
list->next = pool->list;
|
426
|
-
pool->list = list;
|
427
|
-
}
|
428
|
-
pool_unlock(pool);
|
429
|
-
return method;
|
430
|
-
}
|
431
|
-
static void
|
432
|
-
method_handle_free(MethodHandle* method)
|
433
|
-
{
|
434
|
-
MethodHandlePool* pool = method->pool;
|
435
|
-
pool_lock(pool);
|
436
|
-
method->next = pool->list;
|
437
|
-
pool->list = method;
|
438
|
-
pool_unlock(pool);
|
439
|
-
}
|
440
|
-
#endif /* _WIN32 */
|
441
|
-
|
442
|
-
typedef union {
|
443
|
-
#ifdef USE_RAW
|
444
|
-
signed int s8, s16, s32;
|
445
|
-
unsigned int u8, u16, u32;
|
446
|
-
#else
|
447
|
-
signed char s8;
|
448
|
-
unsigned char u8;
|
449
|
-
signed short s16;
|
450
|
-
unsigned short u16;
|
451
|
-
signed int s32;
|
452
|
-
unsigned int u32;
|
453
|
-
#endif
|
454
|
-
signed long long i64;
|
455
|
-
unsigned long long u64;
|
456
|
-
void* ptr;
|
457
|
-
float f32;
|
458
|
-
double f64;
|
459
|
-
} FFIStorage;
|
460
|
-
|
461
|
-
static inline int
|
462
|
-
getSignedInt(VALUE value, int type, int minValue, int maxValue, const char* typeName, VALUE enums)
|
463
|
-
{
|
464
|
-
int i;
|
465
|
-
if (type == T_SYMBOL && enums != Qnil) {
|
466
|
-
value = rb_funcall(enums, map_symbol_id, 1, value);
|
467
|
-
if (value == Qnil) {
|
468
|
-
rb_raise(rb_eTypeError, "Expected a valid enum constant");
|
469
|
-
}
|
470
|
-
}
|
471
|
-
else if (type != T_FIXNUM && type != T_BIGNUM) {
|
472
|
-
rb_raise(rb_eTypeError, "Expected an Integer parameter");
|
473
|
-
}
|
474
|
-
i = NUM2INT(value);
|
475
|
-
if (i < minValue || i > maxValue) {
|
476
|
-
rb_raise(rb_eRangeError, "Value %d outside %s range", i, typeName);
|
477
|
-
}
|
478
|
-
return i;
|
479
|
-
}
|
480
|
-
|
481
|
-
static inline int
|
482
|
-
getUnsignedInt(VALUE value, int type, int maxValue, const char* typeName)
|
483
|
-
{
|
484
|
-
int i;
|
485
|
-
if (type != T_FIXNUM && type != T_BIGNUM) {
|
486
|
-
rb_raise(rb_eTypeError, "Expected an Integer parameter");
|
487
|
-
}
|
488
|
-
i = NUM2INT(value);
|
489
|
-
if (i < 0 || i > maxValue) {
|
490
|
-
rb_raise(rb_eRangeError, "Value %d outside %s range", i, typeName);
|
491
|
-
}
|
492
|
-
return i;
|
493
|
-
}
|
494
|
-
|
495
|
-
/* Special handling/checking for unsigned 32 bit integers */
|
496
|
-
static inline unsigned int
|
497
|
-
getUnsignedInt32(VALUE value, int type)
|
498
|
-
{
|
499
|
-
long long i;
|
500
|
-
if (type != T_FIXNUM && type != T_BIGNUM) {
|
501
|
-
rb_raise(rb_eTypeError, "Expected an Integer parameter");
|
502
|
-
}
|
503
|
-
i = NUM2LL(value);
|
504
|
-
if (i < 0L || i > 0xffffffffL) {
|
505
|
-
rb_raise(rb_eRangeError, "Value %lld outside unsigned int range", i);
|
506
|
-
}
|
507
|
-
return (unsigned int) i;
|
508
|
-
}
|
509
|
-
|
510
|
-
static void
|
511
|
-
ffi_arg_setup(const Invoker* invoker, int argc, VALUE* argv, NativeType* paramTypes,
|
512
|
-
FFIStorage* paramStorage, void** ffiValues)
|
513
|
-
{
|
514
|
-
VALUE callbackProc = Qnil;
|
515
|
-
FFIStorage* param = ¶mStorage[0];
|
516
|
-
int i, argidx, cbidx, argCount;
|
517
|
-
|
518
|
-
if (invoker->paramCount != -1 && invoker->paramCount != argc) {
|
519
|
-
if (argc == (invoker->paramCount - 1) && invoker->callbackCount == 1 && rb_block_given_p()) {
|
520
|
-
callbackProc = rb_block_proc();
|
521
|
-
} else {
|
522
|
-
rb_raise(rb_eArgError, "wrong number of arguments (%d for %d)", argc, invoker->paramCount);
|
523
|
-
}
|
524
|
-
}
|
525
|
-
argCount = invoker->paramCount != -1 ? invoker->paramCount : argc;
|
526
|
-
for (i = 0, argidx = 0, cbidx = 0; i < argCount; ++i) {
|
527
|
-
int type = argidx < argc ? TYPE(argv[argidx]) : T_NONE;
|
528
|
-
ffiValues[i] = param;
|
529
|
-
switch (paramTypes[i]) {
|
530
|
-
case NATIVE_INT8:
|
531
|
-
param->s8 = getSignedInt(argv[argidx++], type, -128, 127, "char", Qnil);
|
532
|
-
ADJ(param, INT8);
|
533
|
-
break;
|
534
|
-
case NATIVE_INT16:
|
535
|
-
param->s16 = getSignedInt(argv[argidx++], type, -0x8000, 0x7fff, "short", Qnil);
|
536
|
-
ADJ(param, INT16);
|
537
|
-
break;
|
538
|
-
case NATIVE_INT32:
|
539
|
-
case NATIVE_ENUM:
|
540
|
-
param->s32 = getSignedInt(argv[argidx++], type, -0x80000000, 0x7fffffff, "int", invoker->enums);
|
541
|
-
ADJ(param, INT32);
|
542
|
-
break;
|
543
|
-
case NATIVE_BOOL:
|
544
|
-
if (type != T_TRUE && type != T_FALSE) {
|
545
|
-
rb_raise(rb_eTypeError, "Expected a Boolean parameter");
|
546
|
-
}
|
547
|
-
param->s32 = argv[argidx++] == Qtrue;
|
548
|
-
ADJ(param, INT32);
|
549
|
-
break;
|
550
|
-
case NATIVE_UINT8:
|
551
|
-
param->u8 = getUnsignedInt(argv[argidx++], type, 0xff, "unsigned char");
|
552
|
-
ADJ(param, INT8);
|
553
|
-
break;
|
554
|
-
case NATIVE_UINT16:
|
555
|
-
param->u16 = getUnsignedInt(argv[argidx++], type, 0xffff, "unsigned short");
|
556
|
-
ADJ(param, INT16);
|
557
|
-
break;
|
558
|
-
case NATIVE_UINT32:
|
559
|
-
/* Special handling/checking for unsigned 32 bit integers */
|
560
|
-
param->u32 = getUnsignedInt32(argv[argidx++], type);
|
561
|
-
ADJ(param, INT32);
|
562
|
-
break;
|
563
|
-
case NATIVE_INT64:
|
564
|
-
if (type != T_FIXNUM && type != T_BIGNUM) {
|
565
|
-
rb_raise(rb_eTypeError, "Expected an Integer parameter");
|
566
|
-
}
|
567
|
-
param->i64 = NUM2LL(argv[argidx]);
|
568
|
-
ADJ(param, INT64);
|
569
|
-
++argidx;
|
570
|
-
break;
|
571
|
-
case NATIVE_UINT64:
|
572
|
-
if (type != T_FIXNUM && type != T_BIGNUM) {
|
573
|
-
rb_raise(rb_eTypeError, "Expected an Integer parameter");
|
574
|
-
}
|
575
|
-
param->u64 = NUM2ULL(argv[argidx]);
|
576
|
-
ADJ(param, INT64);
|
577
|
-
++argidx;
|
578
|
-
break;
|
579
|
-
case NATIVE_FLOAT32:
|
580
|
-
if (type != T_FLOAT && type != T_FIXNUM) {
|
581
|
-
rb_raise(rb_eTypeError, "Expected a Float parameter");
|
582
|
-
}
|
583
|
-
param->f32 = (float) NUM2DBL(argv[argidx]);
|
584
|
-
ADJ(param, FLOAT32);
|
585
|
-
++argidx;
|
586
|
-
break;
|
587
|
-
case NATIVE_FLOAT64:
|
588
|
-
if (type != T_FLOAT && type != T_FIXNUM) {
|
589
|
-
rb_raise(rb_eTypeError, "Expected a Float parameter");
|
590
|
-
}
|
591
|
-
param->f64 = NUM2DBL(argv[argidx]);
|
592
|
-
ADJ(param, FLOAT64);
|
593
|
-
++argidx;
|
594
|
-
break;
|
595
|
-
case NATIVE_STRING:
|
596
|
-
if (type == T_STRING) {
|
597
|
-
if (rb_safe_level() >= 1 && OBJ_TAINTED(argv[argidx])) {
|
598
|
-
rb_raise(rb_eSecurityError, "Unsafe string parameter");
|
599
|
-
}
|
600
|
-
param->ptr = StringValueCStr(argv[argidx]);
|
601
|
-
} else if (type == T_NIL) {
|
602
|
-
param->ptr = NULL;
|
603
|
-
} else {
|
604
|
-
rb_raise(rb_eArgError, "Invalid String value");
|
605
|
-
}
|
606
|
-
ADJ(param, ADDRESS);
|
607
|
-
++argidx;
|
608
|
-
break;
|
609
|
-
case NATIVE_POINTER:
|
610
|
-
case NATIVE_BUFFER_IN:
|
611
|
-
case NATIVE_BUFFER_OUT:
|
612
|
-
case NATIVE_BUFFER_INOUT:
|
613
|
-
if (type == T_DATA && rb_obj_is_kind_of(argv[argidx], rbffi_AbstractMemoryClass)) {
|
614
|
-
param->ptr = ((AbstractMemory *) DATA_PTR(argv[argidx]))->address;
|
615
|
-
} else if (type == T_DATA && rb_obj_is_kind_of(argv[argidx], rbffi_StructClass)) {
|
616
|
-
AbstractMemory* memory = ((Struct *) DATA_PTR(argv[argidx]))->pointer;
|
617
|
-
param->ptr = memory != NULL ? memory->address : NULL;
|
618
|
-
} else if (type == T_STRING) {
|
619
|
-
if (rb_safe_level() >= 1 && OBJ_TAINTED(argv[argidx])) {
|
620
|
-
rb_raise(rb_eSecurityError, "Unsafe string parameter");
|
621
|
-
}
|
622
|
-
param->ptr = StringValuePtr(argv[argidx]);
|
623
|
-
} else if (type == T_NIL) {
|
624
|
-
param->ptr = NULL;
|
625
|
-
} else if (rb_respond_to(argv[argidx], to_ptr)) {
|
626
|
-
VALUE ptr = rb_funcall2(argv[argidx], to_ptr, 0, NULL);
|
627
|
-
if (rb_obj_is_kind_of(ptr, rbffi_AbstractMemoryClass) && TYPE(ptr) == T_DATA) {
|
628
|
-
param->ptr = ((AbstractMemory *) DATA_PTR(ptr))->address;
|
629
|
-
} else {
|
630
|
-
rb_raise(rb_eArgError, "to_ptr returned an invalid pointer");
|
631
|
-
}
|
632
|
-
|
633
|
-
} else {
|
634
|
-
rb_raise(rb_eArgError, ":pointer argument is not a valid pointer");
|
635
|
-
}
|
636
|
-
ADJ(param, ADDRESS);
|
637
|
-
++argidx;
|
638
|
-
break;
|
639
|
-
case NATIVE_CALLBACK:
|
640
|
-
if (callbackProc != Qnil) {
|
641
|
-
param->ptr = callback_param(callbackProc, invoker->callbackParameters[cbidx++]);
|
642
|
-
} else {
|
643
|
-
param->ptr = callback_param(argv[argidx], invoker->callbackParameters[cbidx++]);
|
644
|
-
++argidx;
|
645
|
-
}
|
646
|
-
ADJ(param, ADDRESS);
|
647
|
-
break;
|
648
|
-
default:
|
649
|
-
rb_raise(rb_eArgError, "Invalid parameter type: %d", paramTypes[i]);
|
650
|
-
}
|
651
|
-
}
|
652
|
-
}
|
653
|
-
static inline VALUE
|
654
|
-
ffi_invoke(ffi_cif* cif, Invoker* invoker, void** ffiValues)
|
655
|
-
{
|
656
|
-
FFIStorage retval;
|
657
|
-
|
658
|
-
#ifdef USE_RAW
|
659
|
-
ffi_raw_call(cif, FFI_FN(invoker->function), &retval, (ffi_raw *) ffiValues[0]);
|
660
|
-
#else
|
661
|
-
ffi_call(cif, FFI_FN(invoker->function), &retval, ffiValues);
|
662
|
-
#endif
|
663
|
-
rbffi_save_errno();
|
664
|
-
|
665
|
-
return rbffi_NativeValue_ToRuby(invoker->returnType, invoker->rbReturnType, &retval,
|
666
|
-
invoker->enums);
|
667
|
-
}
|
668
|
-
|
669
|
-
static VALUE
|
670
|
-
invoker_call(int argc, VALUE* argv, VALUE self)
|
671
|
-
{
|
672
|
-
Invoker* invoker;
|
673
|
-
int argCount;
|
674
|
-
FFIStorage params_[MAX_FIXED_ARITY], *params = ¶ms_[0];
|
675
|
-
void* ffiValues_[MAX_FIXED_ARITY], **ffiValues = &ffiValues_[0];
|
676
|
-
|
677
|
-
Data_Get_Struct(self, Invoker, invoker);
|
678
|
-
|
679
|
-
argCount = invoker->paramCount != -1 ? invoker->paramCount : argc;
|
680
|
-
|
681
|
-
if (argCount > MAX_FIXED_ARITY) {
|
682
|
-
params = ALLOCA_N(FFIStorage, argCount);
|
683
|
-
ffiValues = ALLOCA_N(void *, argCount);
|
684
|
-
}
|
685
|
-
|
686
|
-
ffi_arg_setup(invoker, argc, argv, invoker->paramTypes, params, ffiValues);
|
687
|
-
|
688
|
-
return ffi_invoke(&invoker->cif, invoker, ffiValues);
|
689
|
-
}
|
690
|
-
|
691
|
-
#ifdef USE_RAW
|
692
|
-
|
693
|
-
/*
|
694
|
-
* attached_method_invoke is used as the <= 3 argument fixed-arity fast path
|
695
|
-
*/
|
696
|
-
static void
|
697
|
-
attached_method_invoke(ffi_cif* cif, void* retval, ffi_raw* parameters, void* user_data)
|
698
|
-
{
|
699
|
-
MethodHandle* handle = (MethodHandle *) user_data;
|
700
|
-
Invoker* invoker = handle->invoker;
|
701
|
-
void* ffiValues[MAX_FIXED_ARITY];
|
702
|
-
FFIStorage params[MAX_FIXED_ARITY];
|
703
|
-
|
704
|
-
if (invoker->paramCount > 0) {
|
705
|
-
ffi_arg_setup(invoker, invoker->paramCount, (VALUE *)¶meters[1],
|
706
|
-
invoker->paramTypes, params, ffiValues);
|
707
|
-
}
|
708
|
-
*((VALUE *) retval) = ffi_invoke(&invoker->cif, invoker, ffiValues);
|
709
|
-
}
|
710
|
-
|
711
|
-
/*
|
712
|
-
* attached_method_vinvoke is used functions with more than 3 parameters
|
713
|
-
*/
|
714
|
-
static void
|
715
|
-
attached_method_vinvoke(ffi_cif* cif, void* retval, ffi_raw* parameters, void* user_data)
|
716
|
-
{
|
717
|
-
MethodHandle* handle = (MethodHandle *) user_data;
|
718
|
-
Invoker* invoker = handle->invoker;
|
719
|
-
void** ffiValues = ALLOCA_N(void *, invoker->paramCount);
|
720
|
-
FFIStorage* params = ALLOCA_N(FFIStorage, invoker->paramCount);
|
721
|
-
int argc = parameters[0].sint;
|
722
|
-
VALUE* argv = *(VALUE **) ¶meters[1];
|
723
|
-
|
724
|
-
ffi_arg_setup(invoker, argc, argv, invoker->paramTypes, params, ffiValues);
|
725
|
-
*((VALUE *) retval) = ffi_invoke(&invoker->cif, invoker, ffiValues);
|
726
|
-
}
|
727
|
-
|
728
|
-
#else
|
729
|
-
#ifndef _WIN32
|
730
|
-
static void
|
731
|
-
attached_method_invoke(ffi_cif* cif, void* retval, void** parameters, void* user_data)
|
732
|
-
{
|
733
|
-
MethodHandle* handle = (MethodHandle *) user_data;
|
734
|
-
Invoker* invoker = handle->invoker;
|
735
|
-
void* ffiValues[MAX_FIXED_ARITY];
|
736
|
-
FFIStorage params[MAX_FIXED_ARITY];
|
737
|
-
VALUE argv[MAX_FIXED_ARITY];
|
738
|
-
int i;
|
739
|
-
//printf("Attached method invoke nargs=%d paramCount=%d\n", cif->nargs, invoker->paramCount); fflush(stdout);
|
740
|
-
for (i = 0; i < invoker->paramCount; ++i) {
|
741
|
-
memcpy(&argv[i], parameters[i + 1], sizeof(argv[i]));
|
742
|
-
}
|
743
|
-
if (invoker->paramCount > 0) {
|
744
|
-
ffi_arg_setup(invoker, invoker->paramCount, argv, invoker->paramTypes, params, ffiValues);
|
745
|
-
}
|
746
|
-
*((VALUE *) retval) = ffi_invoke(&invoker->cif, invoker, ffiValues);
|
747
|
-
}
|
748
|
-
#endif /* _WIN32 */
|
749
|
-
static void
|
750
|
-
attached_method_vinvoke(ffi_cif* cif, void* retval, void** parameters, void* user_data)
|
751
|
-
{
|
752
|
-
MethodHandle* handle = (MethodHandle *) user_data;
|
753
|
-
Invoker* invoker = handle->invoker;
|
754
|
-
void** ffiValues = ALLOCA_N(void *, invoker->paramCount);
|
755
|
-
FFIStorage* params = ALLOCA_N(FFIStorage, invoker->paramCount);
|
756
|
-
int argc = *(int *) parameters[0];
|
757
|
-
VALUE* argv = *(VALUE **) parameters[1];
|
758
|
-
|
759
|
-
ffi_arg_setup(invoker, argc, argv, invoker->paramTypes, params, ffiValues);
|
760
|
-
*((VALUE *) retval) = ffi_invoke(&invoker->cif, invoker, ffiValues);
|
761
|
-
}
|
762
|
-
#endif
|
763
|
-
|
764
|
-
static VALUE
|
765
|
-
invoker_attach(VALUE self, VALUE module, VALUE name)
|
766
|
-
{
|
767
|
-
Invoker* invoker;
|
768
|
-
MethodHandle* handle;
|
769
|
-
char var[1024];
|
770
|
-
|
771
|
-
Data_Get_Struct(self, Invoker, invoker);
|
772
|
-
if (invoker->paramCount == -1) {
|
773
|
-
rb_raise(rb_eRuntimeError, "Cannot attach variadic invokers");
|
774
|
-
}
|
775
|
-
|
776
|
-
handle = invoker->methodHandle;
|
777
|
-
rb_define_module_function(module, StringValueCStr(name),
|
778
|
-
handle->code, handle->arity);
|
779
|
-
snprintf(var, sizeof(var), "@@%s", StringValueCStr(name));
|
780
|
-
rb_cv_set(module, var, self);
|
781
|
-
rb_define_method(module, StringValueCStr(name),
|
782
|
-
handle->code, handle->arity);
|
783
|
-
return self;
|
784
|
-
}
|
785
|
-
static VALUE
|
786
|
-
invoker_arity(VALUE self)
|
787
|
-
{
|
788
|
-
Invoker* invoker;
|
789
|
-
Data_Get_Struct(self, Invoker, invoker);
|
790
|
-
return INT2FIX(invoker->paramCount);
|
791
|
-
}
|
792
|
-
|
793
|
-
static void
|
794
|
-
invoker_mark(Invoker *invoker)
|
795
|
-
{
|
796
|
-
if (invoker->callbackCount > 0) {
|
797
|
-
rb_gc_mark_locations(&invoker->callbackParameters[0], &invoker->callbackParameters[invoker->callbackCount]);
|
798
|
-
}
|
799
|
-
if (invoker->address != Qnil) {
|
800
|
-
rb_gc_mark(invoker->address);
|
801
|
-
}
|
802
|
-
if (invoker->enums != Qnil) {
|
803
|
-
rb_gc_mark(invoker->enums);
|
804
|
-
}
|
805
|
-
if (invoker->rbReturnType != Qnil) {
|
806
|
-
rb_gc_mark(invoker->rbReturnType);
|
807
|
-
}
|
808
|
-
}
|
809
|
-
|
810
|
-
static void
|
811
|
-
invoker_free(Invoker *invoker)
|
812
|
-
{
|
813
|
-
if (invoker != NULL) {
|
814
|
-
if (invoker->paramTypes != NULL) {
|
815
|
-
xfree(invoker->paramTypes);
|
816
|
-
invoker->paramTypes = NULL;
|
817
|
-
}
|
818
|
-
if (invoker->ffiParamTypes != NULL) {
|
819
|
-
xfree(invoker->ffiParamTypes);
|
820
|
-
invoker->ffiParamTypes = NULL;
|
821
|
-
}
|
822
|
-
if (invoker->callbackParameters != NULL) {
|
823
|
-
xfree(invoker->callbackParameters);
|
824
|
-
invoker->callbackParameters = NULL;
|
825
|
-
}
|
826
|
-
if (invoker->methodHandle != NULL) {
|
827
|
-
method_handle_free(invoker->methodHandle);
|
828
|
-
}
|
829
|
-
xfree(invoker);
|
830
|
-
}
|
831
|
-
}
|
832
|
-
|
833
|
-
static VALUE
|
834
|
-
variadic_invoker_call(VALUE self, VALUE parameterTypes, VALUE parameterValues)
|
835
|
-
{
|
836
|
-
Invoker* invoker;
|
837
|
-
FFIStorage* params;
|
838
|
-
ffi_cif cif;
|
839
|
-
void** ffiValues;
|
840
|
-
ffi_type** ffiParamTypes;
|
841
|
-
ffi_type* ffiReturnType;
|
842
|
-
NativeType* paramTypes;
|
843
|
-
VALUE* argv;
|
844
|
-
int paramCount = 0, i;
|
845
|
-
ffi_status ffiStatus;
|
846
|
-
|
847
|
-
Check_Type(parameterTypes, T_ARRAY);
|
848
|
-
Check_Type(parameterValues, T_ARRAY);
|
849
|
-
|
850
|
-
Data_Get_Struct(self, Invoker, invoker);
|
851
|
-
paramCount = RARRAY_LEN(parameterTypes);
|
852
|
-
paramTypes = ALLOCA_N(NativeType, paramCount);
|
853
|
-
ffiParamTypes = ALLOCA_N(ffi_type *, paramCount);
|
854
|
-
params = ALLOCA_N(FFIStorage, paramCount);
|
855
|
-
ffiValues = ALLOCA_N(void*, paramCount);
|
856
|
-
argv = ALLOCA_N(VALUE, paramCount);
|
857
|
-
|
858
|
-
for (i = 0; i < paramCount; ++i) {
|
859
|
-
VALUE entry = rb_ary_entry(parameterTypes, i);
|
860
|
-
int paramType = rbffi_Type_GetIntValue(entry);
|
861
|
-
switch (paramType) {
|
862
|
-
case NATIVE_INT8:
|
863
|
-
case NATIVE_INT16:
|
864
|
-
case NATIVE_INT32:
|
865
|
-
case NATIVE_ENUM:
|
866
|
-
paramType = NATIVE_INT32;
|
867
|
-
break;
|
868
|
-
case NATIVE_UINT8:
|
869
|
-
case NATIVE_UINT16:
|
870
|
-
case NATIVE_UINT32:
|
871
|
-
paramType = NATIVE_UINT32;
|
872
|
-
break;
|
873
|
-
case NATIVE_FLOAT32:
|
874
|
-
paramType = NATIVE_FLOAT64;
|
875
|
-
break;
|
876
|
-
}
|
877
|
-
paramTypes[i] = paramType;
|
878
|
-
ffiParamTypes[i] = rbffi_NativeType_ToFFI(paramType);
|
879
|
-
if (ffiParamTypes[i] == NULL) {
|
880
|
-
rb_raise(rb_eArgError, "Invalid parameter type #%x", paramType);
|
881
|
-
}
|
882
|
-
argv[i] = rb_ary_entry(parameterValues, i);
|
883
|
-
}
|
884
|
-
|
885
|
-
ffiReturnType = invoker->returnType->ffiType;
|
886
|
-
if (ffiReturnType == NULL) {
|
887
|
-
rb_raise(rb_eArgError, "Invalid return type");
|
888
|
-
}
|
889
|
-
ffiStatus = ffi_prep_cif(&cif, invoker->abi, paramCount, ffiReturnType, ffiParamTypes);
|
890
|
-
switch (ffiStatus) {
|
891
|
-
case FFI_BAD_ABI:
|
892
|
-
rb_raise(rb_eArgError, "Invalid ABI specified");
|
893
|
-
case FFI_BAD_TYPEDEF:
|
894
|
-
rb_raise(rb_eArgError, "Invalid argument type specified");
|
895
|
-
case FFI_OK:
|
896
|
-
break;
|
897
|
-
default:
|
898
|
-
rb_raise(rb_eArgError, "Unknown FFI error");
|
899
|
-
}
|
900
|
-
ffi_arg_setup(invoker, paramCount, argv, paramTypes, params, ffiValues);
|
901
|
-
return ffi_invoke(&cif, invoker, ffiValues);
|
902
|
-
}
|
903
|
-
|
904
|
-
static void*
|
905
|
-
callback_param(VALUE proc, VALUE cbInfo)
|
906
|
-
{
|
907
|
-
VALUE callback ;
|
908
|
-
if (proc == Qnil) {
|
909
|
-
return NULL ;
|
910
|
-
}
|
911
|
-
callback = rbffi_NativeCallback_ForProc(proc, cbInfo);
|
912
|
-
return ((NativeCallback *) DATA_PTR(callback))->code;
|
913
|
-
}
|
914
|
-
|
915
|
-
void
|
916
|
-
rbffi_Invoker_Init(VALUE moduleFFI)
|
917
|
-
{
|
918
|
-
ffi_type* ffiValueType;
|
919
|
-
int i;
|
920
|
-
|
921
|
-
rbffi_InvokerClass = classInvoker = rb_define_class_under(moduleFFI, "Invoker", rb_cObject);
|
922
|
-
rb_global_variable(&rbffi_InvokerClass);
|
923
|
-
rb_global_variable(&classInvoker);
|
924
|
-
|
925
|
-
rb_define_alloc_func(classInvoker, invoker_allocate);
|
926
|
-
rb_define_method(classInvoker, "initialize", invoker_initialize, 6);
|
927
|
-
rb_define_method(classInvoker, "call", invoker_call, -1);
|
928
|
-
rb_define_alias(classInvoker, "call0", "call");
|
929
|
-
rb_define_alias(classInvoker, "call1", "call");
|
930
|
-
rb_define_alias(classInvoker, "call2", "call");
|
931
|
-
rb_define_alias(classInvoker, "call3", "call");
|
932
|
-
rb_define_method(classInvoker, "arity", invoker_arity, 0);
|
933
|
-
rb_define_method(classInvoker, "attach", invoker_attach, 2);
|
934
|
-
classVariadicInvoker = rb_define_class_under(moduleFFI, "VariadicInvoker", rb_cObject);
|
935
|
-
rb_global_variable(&classVariadicInvoker);
|
936
|
-
|
937
|
-
rb_define_singleton_method(classVariadicInvoker, "__new", variadic_invoker_new, 5);
|
938
|
-
rb_define_method(classVariadicInvoker, "invoke", variadic_invoker_call, 2);
|
939
|
-
rb_define_alias(classVariadicInvoker, "call", "invoke");
|
940
|
-
|
941
|
-
to_ptr = rb_intern("to_ptr");
|
942
|
-
map_symbol_id = rb_intern("__map_symbol");
|
943
|
-
|
944
|
-
ffiValueType = (sizeof (VALUE) == sizeof (long))
|
945
|
-
? &ffi_type_ulong : &ffi_type_uint64;
|
946
|
-
for (i = 0; i <= MAX_FIXED_ARITY + 1; ++i) {
|
947
|
-
methodHandleParamTypes[i] = ffiValueType;
|
948
|
-
}
|
949
|
-
methodHandleVarargParamTypes[2] = ffiValueType;
|
950
|
-
|
951
|
-
#ifndef _WIN32
|
952
|
-
PageSize = sysconf(_SC_PAGESIZE);
|
953
|
-
#endif /* _WIN32 */
|
954
|
-
|
955
|
-
#if defined(USE_PTHREAD_LOCAL)
|
956
|
-
for (i = 0; i < 4; ++i) {
|
957
|
-
pthread_mutex_init(&methodHandlePool[i].mutex, NULL);
|
958
|
-
}
|
959
|
-
pthread_mutex_init(&defaultMethodHandlePool.mutex, NULL);
|
960
|
-
#endif /* USE_PTHREAD_LOCAL */
|
961
|
-
|
962
|
-
}
|