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.

Files changed (55) hide show
  1. data/README.rdoc +15 -15
  2. data/Rakefile +57 -8
  3. data/ext/ffi_c/AbstractMemory.c +101 -24
  4. data/ext/ffi_c/AbstractMemory.h +98 -6
  5. data/ext/ffi_c/ArrayType.c +129 -0
  6. data/ext/ffi_c/ArrayType.h +58 -0
  7. data/ext/ffi_c/AutoPointer.c +1 -0
  8. data/ext/ffi_c/Buffer.c +59 -43
  9. data/ext/ffi_c/Call.c +853 -0
  10. data/ext/ffi_c/Call.h +86 -0
  11. data/ext/ffi_c/ClosurePool.c +302 -0
  12. data/ext/ffi_c/ClosurePool.h +29 -0
  13. data/ext/ffi_c/DynamicLibrary.c +3 -0
  14. data/ext/ffi_c/Function.c +478 -0
  15. data/ext/ffi_c/Function.h +80 -0
  16. data/ext/ffi_c/FunctionInfo.c +221 -0
  17. data/ext/ffi_c/LastError.c +30 -6
  18. data/ext/ffi_c/MemoryPointer.c +50 -28
  19. data/ext/ffi_c/MethodHandle.c +346 -0
  20. data/ext/ffi_c/MethodHandle.h +53 -0
  21. data/ext/ffi_c/Pointer.c +73 -13
  22. data/ext/ffi_c/Pointer.h +31 -7
  23. data/ext/ffi_c/Struct.c +517 -224
  24. data/ext/ffi_c/Struct.h +60 -6
  25. data/ext/ffi_c/StructByValue.c +140 -0
  26. data/ext/ffi_c/StructByValue.h +53 -0
  27. data/ext/ffi_c/StructLayout.c +450 -0
  28. data/ext/ffi_c/Type.c +121 -22
  29. data/ext/ffi_c/Type.h +37 -8
  30. data/ext/ffi_c/Types.c +46 -61
  31. data/ext/ffi_c/Types.h +38 -7
  32. data/ext/ffi_c/Variadic.c +260 -0
  33. data/ext/ffi_c/compat.h +53 -3
  34. data/ext/ffi_c/extconf.rb +6 -7
  35. data/ext/ffi_c/ffi.c +45 -39
  36. data/ext/ffi_c/libffi.darwin.mk +2 -2
  37. data/ext/ffi_c/rbffi.h +3 -0
  38. data/lib/ffi/ffi.rb +7 -4
  39. data/lib/ffi/library.rb +34 -59
  40. data/lib/ffi/platform.rb +14 -4
  41. data/lib/ffi/struct.rb +110 -281
  42. data/lib/ffi/union.rb +4 -9
  43. data/lib/ffi/variadic.rb +1 -6
  44. data/spec/ffi/buffer_spec.rb +6 -0
  45. data/spec/ffi/callback_spec.rb +34 -3
  46. data/spec/ffi/function_spec.rb +73 -0
  47. data/spec/ffi/library_spec.rb +56 -52
  48. data/spec/ffi/pointer_spec.rb +3 -3
  49. data/spec/ffi/struct_callback_spec.rb +26 -3
  50. data/spec/ffi/struct_spec.rb +56 -3
  51. metadata +42 -11
  52. data/ext/ffi_c/Callback.c +0 -374
  53. data/ext/ffi_c/Callback.h +0 -47
  54. data/ext/ffi_c/Invoker.c +0 -962
  55. 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 = &paramStorage[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 = &params_[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 *)&parameters[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 **) &parameters[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
- }