ffi 0.3.1 → 0.4.0

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.
Files changed (76) hide show
  1. data/README.rdoc +51 -1
  2. data/Rakefile +38 -28
  3. data/ext/ffi_c/AbstractMemory.c +74 -70
  4. data/ext/ffi_c/AbstractMemory.h +8 -4
  5. data/ext/ffi_c/AutoPointer.c +8 -9
  6. data/ext/ffi_c/AutoPointer.h +2 -2
  7. data/ext/ffi_c/Buffer.c +42 -24
  8. data/ext/ffi_c/Callback.c +85 -33
  9. data/ext/ffi_c/Callback.h +11 -5
  10. data/ext/ffi_c/{NativeLibrary.c → DynamicLibrary.c} +83 -16
  11. data/ext/ffi_c/{NativeLibrary.h → DynamicLibrary.h} +1 -1
  12. data/ext/ffi_c/Invoker.c +152 -192
  13. data/ext/ffi_c/LastError.c +135 -0
  14. data/ext/ffi_c/LastError.h +18 -0
  15. data/ext/ffi_c/MemoryPointer.c +27 -20
  16. data/ext/ffi_c/MemoryPointer.h +3 -3
  17. data/ext/ffi_c/NullPointer.c +51 -47
  18. data/ext/ffi_c/Platform.c +9 -10
  19. data/ext/ffi_c/Platform.h +1 -1
  20. data/ext/ffi_c/Pointer.c +52 -21
  21. data/ext/ffi_c/Pointer.h +8 -6
  22. data/ext/ffi_c/Struct.c +70 -61
  23. data/ext/ffi_c/Struct.h +2 -2
  24. data/ext/ffi_c/Type.c +230 -0
  25. data/ext/ffi_c/Type.h +28 -0
  26. data/ext/ffi_c/Types.c +48 -6
  27. data/ext/ffi_c/Types.h +8 -2
  28. data/ext/ffi_c/endian.h +40 -0
  29. data/ext/ffi_c/extconf.rb +6 -5
  30. data/ext/ffi_c/ffi.c +21 -44
  31. data/ext/ffi_c/libffi.bsd.mk +34 -0
  32. data/ext/ffi_c/libffi.darwin.mk +30 -10
  33. data/ext/ffi_c/libffi.gnu.mk +29 -0
  34. data/ext/ffi_c/libffi.mk +4 -2
  35. data/ext/ffi_c/rbffi.h +6 -8
  36. data/gen/Rakefile +12 -0
  37. data/lib/ffi/autopointer.rb +1 -1
  38. data/lib/ffi/enum.rb +78 -0
  39. data/lib/ffi/ffi.rb +5 -6
  40. data/lib/ffi/io.rb +15 -1
  41. data/lib/ffi/library.rb +79 -18
  42. data/lib/ffi/pointer.rb +2 -2
  43. data/lib/ffi/struct.rb +68 -14
  44. data/lib/ffi/types.rb +6 -3
  45. data/lib/ffi/variadic.rb +2 -2
  46. data/lib/ffi.rb +10 -1
  47. data/spec/ffi/bool_spec.rb +24 -0
  48. data/spec/ffi/callback_spec.rb +217 -17
  49. data/spec/ffi/enum_spec.rb +164 -0
  50. data/spec/ffi/managed_struct_spec.rb +6 -1
  51. data/spec/ffi/number_spec.rb +30 -0
  52. data/spec/ffi/pointer_spec.rb +33 -8
  53. data/spec/ffi/rbx/memory_pointer_spec.rb +0 -6
  54. data/spec/ffi/spec_helper.rb +5 -1
  55. data/spec/ffi/string_spec.rb +65 -4
  56. data/spec/ffi/struct_callback_spec.rb +41 -0
  57. data/spec/ffi/struct_initialize_spec.rb +30 -0
  58. data/spec/ffi/struct_spec.rb +44 -21
  59. metadata +31 -69
  60. data/ext/ffi_c/ffi.mk +0 -23
  61. data/nbproject/Makefile-Default.mk +0 -57
  62. data/nbproject/Makefile-impl.mk +0 -123
  63. data/nbproject/Package-Default.bash +0 -72
  64. data/nbproject/configurations.xml +0 -293
  65. data/nbproject/private/configurations.xml +0 -22
  66. data/nbproject/private/private.xml +0 -7
  67. data/nbproject/project.properties +0 -0
  68. data/nbproject/project.xml +0 -15
  69. data/samples/getlogin.rb +0 -7
  70. data/samples/getpid.rb +0 -7
  71. data/samples/gettimeofday.rb +0 -17
  72. data/samples/hello.rb +0 -6
  73. data/samples/inotify.rb +0 -59
  74. data/samples/pty.rb +0 -75
  75. data/samples/qsort.rb +0 -20
  76. data/samples/sample_helper.rb +0 -6
data/ext/ffi_c/Invoker.c CHANGED
@@ -6,14 +6,14 @@
6
6
  #include <stdio.h>
7
7
  #include <stdint.h>
8
8
  #include <stdbool.h>
9
- #include <unistd.h>
9
+ #ifndef _WIN32
10
+ # include <unistd.h>
11
+ # include <pthread.h>
12
+ #endif
10
13
  #include <errno.h>
11
14
  #include <ruby.h>
12
15
 
13
16
  #include <ffi.h>
14
- #if defined(HAVE_NATIVETHREAD) && !defined(_WIN32) && !defined(__WIN32__)
15
- # include <pthread.h>
16
- #endif
17
17
  #include "rbffi.h"
18
18
  #include "compat.h"
19
19
 
@@ -23,6 +23,8 @@
23
23
  #include "Platform.h"
24
24
  #include "Callback.h"
25
25
  #include "Types.h"
26
+ #include "Type.h"
27
+ #include "LastError.h"
26
28
 
27
29
  #if defined(__i386__) && !defined(_WIN32) && !defined(__WIN32__)
28
30
  # define USE_RAW
@@ -32,17 +34,23 @@
32
34
  #endif
33
35
  #define MAX_FIXED_ARITY (3)
34
36
 
37
+ #ifndef roundup
38
+ # define roundup(x, y) ((((x)+((y)-1))/(y))*(y))
39
+ #endif
40
+
35
41
  typedef struct MethodHandle MethodHandle;
36
42
  typedef struct Invoker Invoker;
37
43
 
38
44
  struct Invoker {
39
- VALUE library;
45
+ VALUE address;
46
+ VALUE enums;
40
47
  void* function;
41
48
  ffi_cif cif;
42
49
  int paramCount;
43
50
  ffi_type** ffiParamTypes;
44
51
  NativeType* paramTypes;
45
- NativeType returnType;
52
+ Type* returnType;
53
+ VALUE rbReturnType;
46
54
  VALUE callbackArray;
47
55
  int callbackCount;
48
56
  VALUE* callbackParameters;
@@ -72,16 +80,13 @@ struct MethodHandlePool {
72
80
  MethodHandle* list;
73
81
  };
74
82
  #endif /* _WIN32 */
75
- typedef struct ThreadData {
76
- int td_errno;
77
- } ThreadData;
83
+
78
84
  static VALUE invoker_allocate(VALUE klass);
79
- static VALUE invoker_initialize(VALUE self, VALUE library, VALUE function, VALUE parameterTypes,
80
- VALUE returnType, VALUE convention);
85
+ static VALUE invoker_initialize(VALUE self, VALUE function, VALUE parameterTypes,
86
+ VALUE rbReturnType, VALUE returnType, VALUE convention, VALUE enums);
81
87
  static void invoker_mark(Invoker *);
82
88
  static void invoker_free(Invoker *);
83
89
  static VALUE invoker_call(int argc, VALUE* argv, VALUE self);
84
- static VALUE invoker_call0(VALUE self);
85
90
  static VALUE invoker_arity(VALUE self);
86
91
  static void* callback_param(VALUE proc, VALUE cbinfo);
87
92
  #ifdef USE_RAW
@@ -96,19 +101,15 @@ static void attached_method_vinvoke(ffi_cif* cif, void* retval, void** parameter
96
101
  static MethodHandle* method_handle_alloc(int arity);
97
102
  static void method_handle_free(MethodHandle *);
98
103
 
99
- static inline ThreadData* thread_data_get(void);
100
104
 
101
105
  #ifndef _WIN32
102
106
  static int PageSize;
103
107
  #endif
104
- static VALUE classInvoker = Qnil, classVariadicInvoker = Qnil;
105
- static ID to_ptr;
106
-
107
- #if defined(USE_PTHREAD_LOCAL)
108
- static pthread_key_t threadDataKey;
109
- #endif
110
108
 
111
- #define threadData (thread_data_get())
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;
112
113
 
113
114
  #ifdef USE_RAW
114
115
  # ifndef __i386__
@@ -142,12 +143,19 @@ static VALUE
142
143
  invoker_allocate(VALUE klass)
143
144
  {
144
145
  Invoker *invoker;
145
- return Data_Make_Struct(klass, Invoker, invoker_mark, invoker_free, 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;
146
154
  }
147
155
 
148
156
  static VALUE
149
- invoker_initialize(VALUE self, VALUE library, VALUE function, VALUE parameterTypes,
150
- VALUE returnType, VALUE convention)
157
+ invoker_initialize(VALUE self, VALUE function, VALUE parameterTypes,
158
+ VALUE rbReturnTypeSymbol, VALUE returnType, VALUE convention, VALUE enums)
151
159
  {
152
160
  Invoker* invoker = NULL;
153
161
  ffi_type* ffiReturnType;
@@ -156,39 +164,45 @@ invoker_initialize(VALUE self, VALUE library, VALUE function, VALUE parameterTyp
156
164
  int i;
157
165
 
158
166
  Check_Type(parameterTypes, T_ARRAY);
159
- Check_Type(returnType, T_FIXNUM);
167
+ Check_Type(rbReturnTypeSymbol, T_SYMBOL);
160
168
  Check_Type(convention, T_STRING);
161
- Check_Type(library, T_DATA);
162
169
  Check_Type(function, T_DATA);
163
170
 
164
171
  Data_Get_Struct(self, Invoker, invoker);
165
- invoker->library = library;
166
- invoker->function = rb_FFI_AbstractMemory_cast(function, rb_FFI_Pointer_class)->address;
172
+ invoker->enums = enums;
173
+ invoker->address = function;
174
+ invoker->function = rbffi_AbstractMemory_Cast(function, rbffi_PointerClass)->address;
167
175
  invoker->paramCount = RARRAY_LEN(parameterTypes);
168
176
  invoker->paramTypes = ALLOC_N(NativeType, invoker->paramCount);
169
177
  invoker->ffiParamTypes = ALLOC_N(ffi_type *, invoker->paramCount);
170
178
 
171
179
  for (i = 0; i < invoker->paramCount; ++i) {
172
180
  VALUE entry = rb_ary_entry(parameterTypes, i);
173
- if (rb_obj_is_kind_of(entry, rb_FFI_CallbackInfo_class)) {
181
+ if (rb_obj_is_kind_of(entry, rbffi_CallbackInfoClass)) {
174
182
  invoker->callbackParameters = REALLOC_N(invoker->callbackParameters, VALUE,
175
183
  invoker->callbackCount + 1);
176
184
  invoker->callbackParameters[invoker->callbackCount++] = entry;
177
185
  invoker->paramTypes[i] = NATIVE_CALLBACK;
178
186
  invoker->ffiParamTypes[i] = &ffi_type_pointer;
179
- } else {
180
- int paramType = FIX2INT(entry);
187
+ } else if (rb_obj_is_kind_of(entry, rbffi_TypeClass)){
188
+ int paramType = rbffi_Type_GetIntValue(entry);
181
189
  invoker->paramTypes[i] = paramType;
182
- invoker->ffiParamTypes[i] = rb_FFI_NativeTypeToFFI(paramType);
190
+ invoker->ffiParamTypes[i] = rbffi_NativeType_ToFFI(paramType);
183
191
  }
184
192
  if (invoker->ffiParamTypes[i] == NULL) {
185
- rb_raise(rb_eArgError, "Invalid parameter type");
193
+ rb_raise(rb_eTypeError, "Invalid parameter type");
186
194
  }
187
195
  }
188
- invoker->returnType = FIX2INT(returnType);
189
- ffiReturnType = rb_FFI_NativeTypeToFFI(invoker->returnType);
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;
190
204
  if (ffiReturnType == NULL) {
191
- rb_raise(rb_eArgError, "Invalid return type");
205
+ rb_raise(rb_eTypeError, "Invalid return type");
192
206
  }
193
207
  #if defined(_WIN32) || defined(__WIN32__)
194
208
  abi = strcmp(StringValueCStr(convention), "stdcall") == 0 ? FFI_STDCALL : FFI_DEFAULT_ABI;
@@ -213,25 +227,31 @@ invoker_initialize(VALUE self, VALUE library, VALUE function, VALUE parameterTyp
213
227
  }
214
228
 
215
229
  static VALUE
216
- variadic_invoker_new(VALUE klass, VALUE library, VALUE function, VALUE returnType, VALUE convention)
230
+ variadic_invoker_new(VALUE klass, VALUE function, VALUE rbReturnTypeSymbol, VALUE returnType, VALUE convention, VALUE enums)
217
231
  {
218
232
  Invoker* invoker = NULL;
219
233
  VALUE retval = Qnil;
220
234
 
221
- Check_Type(returnType, T_FIXNUM);
235
+ Check_Type(rbReturnTypeSymbol, T_SYMBOL);
222
236
  Check_Type(convention, T_STRING);
223
- Check_Type(library, T_DATA);
224
237
  Check_Type(function, T_DATA);
225
238
 
226
239
  retval = Data_Make_Struct(klass, Invoker, invoker_mark, invoker_free, invoker);
227
- invoker->library = library;
228
- invoker->function = rb_FFI_AbstractMemory_cast(function, rb_FFI_Pointer_class)->address;
240
+ invoker->enums = enums;
241
+ invoker->address = function;
242
+ invoker->function = rbffi_AbstractMemory_Cast(function, rbffi_PointerClass)->address;
229
243
  #if defined(_WIN32) || defined(__WIN32__)
230
244
  invoker->abi = strcmp(StringValueCStr(convention), "stdcall") == 0 ? FFI_STDCALL : FFI_DEFAULT_ABI;
231
245
  #else
232
246
  invoker->abi = FFI_DEFAULT_ABI;
233
247
  #endif
234
- invoker->returnType = FIX2INT(returnType);
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);
235
255
  invoker->paramCount = -1;
236
256
  return retval;
237
257
  }
@@ -420,7 +440,7 @@ method_handle_free(MethodHandle* method)
420
440
  #endif /* _WIN32 */
421
441
 
422
442
  typedef union {
423
- #if BYTE_ORDER == LITTLE_ENDIAN
443
+ #ifdef USE_RAW
424
444
  signed int s8, s16, s32;
425
445
  unsigned int u8, u16, u32;
426
446
  #else
@@ -439,10 +459,16 @@ typedef union {
439
459
  } FFIStorage;
440
460
 
441
461
  static inline int
442
- getSignedInt(VALUE value, int type, int minValue, int maxValue, const char* typeName)
462
+ getSignedInt(VALUE value, int type, int minValue, int maxValue, const char* typeName, VALUE enums)
443
463
  {
444
464
  int i;
445
- if (type != T_FIXNUM && type != T_BIGNUM) {
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) {
446
472
  rb_raise(rb_eTypeError, "Expected an Integer parameter");
447
473
  }
448
474
  i = NUM2INT(value);
@@ -500,18 +526,25 @@ ffi_arg_setup(const Invoker* invoker, int argc, VALUE* argv, NativeType* paramTy
500
526
  for (i = 0, argidx = 0, cbidx = 0; i < argCount; ++i) {
501
527
  int type = argidx < argc ? TYPE(argv[argidx]) : T_NONE;
502
528
  ffiValues[i] = param;
503
-
504
529
  switch (paramTypes[i]) {
505
530
  case NATIVE_INT8:
506
- param->s8 = getSignedInt(argv[argidx++], type, -128, 127, "char");
531
+ param->s8 = getSignedInt(argv[argidx++], type, -128, 127, "char", Qnil);
507
532
  ADJ(param, INT8);
508
533
  break;
509
534
  case NATIVE_INT16:
510
- param->s16 = getSignedInt(argv[argidx++], type, -0x8000, 0x7fff, "short");
535
+ param->s16 = getSignedInt(argv[argidx++], type, -0x8000, 0x7fff, "short", Qnil);
511
536
  ADJ(param, INT16);
512
537
  break;
513
538
  case NATIVE_INT32:
514
- param->s32 = getSignedInt(argv[argidx++], type, -0x80000000, 0x7fffffff, "int");
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;
515
548
  ADJ(param, INT32);
516
549
  break;
517
550
  case NATIVE_UINT8:
@@ -577,9 +610,9 @@ ffi_arg_setup(const Invoker* invoker, int argc, VALUE* argv, NativeType* paramTy
577
610
  case NATIVE_BUFFER_IN:
578
611
  case NATIVE_BUFFER_OUT:
579
612
  case NATIVE_BUFFER_INOUT:
580
- if (type == T_DATA && rb_obj_is_kind_of(argv[argidx], rb_FFI_AbstractMemory_class)) {
613
+ if (type == T_DATA && rb_obj_is_kind_of(argv[argidx], rbffi_AbstractMemoryClass)) {
581
614
  param->ptr = ((AbstractMemory *) DATA_PTR(argv[argidx]))->address;
582
- } else if (type == T_DATA && rb_obj_is_kind_of(argv[argidx], rb_FFI_Struct_class)) {
615
+ } else if (type == T_DATA && rb_obj_is_kind_of(argv[argidx], rbffi_StructClass)) {
583
616
  AbstractMemory* memory = ((Struct *) DATA_PTR(argv[argidx]))->pointer;
584
617
  param->ptr = memory != NULL ? memory->address : NULL;
585
618
  } else if (type == T_STRING) {
@@ -591,7 +624,7 @@ ffi_arg_setup(const Invoker* invoker, int argc, VALUE* argv, NativeType* paramTy
591
624
  param->ptr = NULL;
592
625
  } else if (rb_respond_to(argv[argidx], to_ptr)) {
593
626
  VALUE ptr = rb_funcall2(argv[argidx], to_ptr, 0, NULL);
594
- if (rb_obj_is_kind_of(ptr, rb_FFI_AbstractMemory_class) && TYPE(ptr) == T_DATA) {
627
+ if (rb_obj_is_kind_of(ptr, rbffi_AbstractMemoryClass) && TYPE(ptr) == T_DATA) {
595
628
  param->ptr = ((AbstractMemory *) DATA_PTR(ptr))->address;
596
629
  } else {
597
630
  rb_raise(rb_eArgError, "to_ptr returned an invalid pointer");
@@ -618,81 +651,48 @@ ffi_arg_setup(const Invoker* invoker, int argc, VALUE* argv, NativeType* paramTy
618
651
  }
619
652
  }
620
653
  static inline VALUE
621
- ffi_invoke(ffi_cif* cif, void* function, NativeType returnType, void** ffiValues)
654
+ ffi_invoke(ffi_cif* cif, Invoker* invoker, void** ffiValues)
622
655
  {
623
656
  FFIStorage retval;
624
- int error = 0;
625
657
 
626
658
  #ifdef USE_RAW
627
- ffi_raw_call(cif, FFI_FN(function), &retval, (ffi_raw *) ffiValues[0]);
628
- #else
629
- ffi_call(cif, FFI_FN(function), &retval, ffiValues);
630
- #endif
631
- #if defined(_WIN32) || defined(__WIN32__)
632
- error = GetLastError();
659
+ ffi_raw_call(cif, FFI_FN(invoker->function), &retval, (ffi_raw *) ffiValues[0]);
633
660
  #else
634
- error = errno;
661
+ ffi_call(cif, FFI_FN(invoker->function), &retval, ffiValues);
635
662
  #endif
636
- threadData->td_errno = error;
663
+ rbffi_save_errno();
637
664
 
638
- return rb_FFI_NativeValueToRuby(returnType, &retval);
665
+ return rbffi_NativeValue_ToRuby(invoker->returnType, invoker->rbReturnType, &retval,
666
+ invoker->enums);
639
667
  }
668
+
640
669
  static VALUE
641
670
  invoker_call(int argc, VALUE* argv, VALUE self)
642
671
  {
643
672
  Invoker* invoker;
644
- FFIStorage params[MAX_PARAMETERS];
645
- void* ffiValues[MAX_PARAMETERS];
673
+ int argCount;
674
+ FFIStorage params_[MAX_FIXED_ARITY], *params = &params_[0];
675
+ void* ffiValues_[MAX_FIXED_ARITY], **ffiValues = &ffiValues_[0];
646
676
 
647
677
  Data_Get_Struct(self, Invoker, invoker);
648
- ffi_arg_setup(invoker, argc, argv, invoker->paramTypes, params, ffiValues);
649
- return ffi_invoke(&invoker->cif, invoker->function, invoker->returnType, ffiValues);
650
- }
651
678
 
652
- static inline VALUE
653
- invoker_callN(VALUE self, int argc, VALUE* argv)
654
- {
655
- Invoker* invoker;
656
- FFIStorage params[3];
657
- void* ffiValues[3];
658
-
659
- Data_Get_Struct(self, Invoker, invoker);
660
- ffi_arg_setup(invoker, argc, argv, invoker->paramTypes, params, ffiValues);
661
- return ffi_invoke(&invoker->cif, invoker->function, invoker->returnType, ffiValues);
662
- }
663
-
664
- static VALUE
665
- invoker_call0(VALUE self)
666
- {
667
- Invoker* invoker;
668
- FFIStorage arg0;
669
- void* ffiValues[] = { &arg0 };
670
-
671
- Data_Get_Struct(self, Invoker, invoker);
672
- return ffi_invoke(&invoker->cif, invoker->function, invoker->returnType, ffiValues);
673
- }
679
+ argCount = invoker->paramCount != -1 ? invoker->paramCount : argc;
674
680
 
675
- static VALUE
676
- invoker_call1(VALUE self, VALUE arg1)
677
- {
678
- return invoker_callN(self, 1, &arg1);
679
- }
681
+ if (argCount > MAX_FIXED_ARITY) {
682
+ params = ALLOCA_N(FFIStorage, argCount);
683
+ ffiValues = ALLOCA_N(void *, argCount);
684
+ }
680
685
 
681
- static VALUE
682
- invoker_call2(VALUE self, VALUE arg1, VALUE arg2)
683
- {
684
- VALUE argv[] = { arg1, arg2 };
685
- return invoker_callN(self, 2, argv);
686
- }
686
+ ffi_arg_setup(invoker, argc, argv, invoker->paramTypes, params, ffiValues);
687
687
 
688
- static VALUE
689
- invoker_call3(VALUE self, VALUE arg1, VALUE arg2, VALUE arg3)
690
- {
691
- VALUE argv[] = { arg1, arg2, arg3 };
692
- return invoker_callN(self, 3, argv);
688
+ return ffi_invoke(&invoker->cif, invoker, ffiValues);
693
689
  }
694
690
 
695
691
  #ifdef USE_RAW
692
+
693
+ /*
694
+ * attached_method_invoke is used as the <= 3 argument fixed-arity fast path
695
+ */
696
696
  static void
697
697
  attached_method_invoke(ffi_cif* cif, void* retval, ffi_raw* parameters, void* user_data)
698
698
  {
@@ -705,9 +705,12 @@ attached_method_invoke(ffi_cif* cif, void* retval, ffi_raw* parameters, void* us
705
705
  ffi_arg_setup(invoker, invoker->paramCount, (VALUE *)&parameters[1],
706
706
  invoker->paramTypes, params, ffiValues);
707
707
  }
708
- *((VALUE *) retval) = ffi_invoke(&invoker->cif, invoker->function, invoker->returnType, ffiValues);
708
+ *((VALUE *) retval) = ffi_invoke(&invoker->cif, invoker, ffiValues);
709
709
  }
710
710
 
711
+ /*
712
+ * attached_method_vinvoke is used functions with more than 3 parameters
713
+ */
711
714
  static void
712
715
  attached_method_vinvoke(ffi_cif* cif, void* retval, ffi_raw* parameters, void* user_data)
713
716
  {
@@ -719,7 +722,7 @@ attached_method_vinvoke(ffi_cif* cif, void* retval, ffi_raw* parameters, void* u
719
722
  VALUE* argv = *(VALUE **) &parameters[1];
720
723
 
721
724
  ffi_arg_setup(invoker, argc, argv, invoker->paramTypes, params, ffiValues);
722
- *((VALUE *) retval) = ffi_invoke(&invoker->cif, invoker->function, invoker->returnType, ffiValues);
725
+ *((VALUE *) retval) = ffi_invoke(&invoker->cif, invoker, ffiValues);
723
726
  }
724
727
 
725
728
  #else
@@ -740,7 +743,7 @@ attached_method_invoke(ffi_cif* cif, void* retval, void** parameters, void* user
740
743
  if (invoker->paramCount > 0) {
741
744
  ffi_arg_setup(invoker, invoker->paramCount, argv, invoker->paramTypes, params, ffiValues);
742
745
  }
743
- *((VALUE *) retval) = ffi_invoke(&invoker->cif, invoker->function, invoker->returnType, ffiValues);
746
+ *((VALUE *) retval) = ffi_invoke(&invoker->cif, invoker, ffiValues);
744
747
  }
745
748
  #endif /* _WIN32 */
746
749
  static void
@@ -754,21 +757,29 @@ attached_method_vinvoke(ffi_cif* cif, void* retval, void** parameters, void* use
754
757
  VALUE* argv = *(VALUE **) parameters[1];
755
758
 
756
759
  ffi_arg_setup(invoker, argc, argv, invoker->paramTypes, params, ffiValues);
757
- *((VALUE *) retval) = ffi_invoke(&invoker->cif, invoker->function, invoker->returnType, ffiValues);
760
+ *((VALUE *) retval) = ffi_invoke(&invoker->cif, invoker, ffiValues);
758
761
  }
759
762
  #endif
763
+
760
764
  static VALUE
761
765
  invoker_attach(VALUE self, VALUE module, VALUE name)
762
766
  {
763
767
  Invoker* invoker;
764
768
  MethodHandle* handle;
765
769
  char var[1024];
770
+
766
771
  Data_Get_Struct(self, Invoker, invoker);
772
+ if (invoker->paramCount == -1) {
773
+ rb_raise(rb_eRuntimeError, "Cannot attach variadic invokers");
774
+ }
775
+
767
776
  handle = invoker->methodHandle;
768
- rb_define_module_function(module, StringValuePtr(name),
777
+ rb_define_module_function(module, StringValueCStr(name),
769
778
  handle->code, handle->arity);
770
779
  snprintf(var, sizeof(var), "@@%s", StringValueCStr(name));
771
780
  rb_cv_set(module, var, self);
781
+ rb_define_method(module, StringValueCStr(name),
782
+ handle->code, handle->arity);
772
783
  return self;
773
784
  }
774
785
  static VALUE
@@ -785,8 +796,14 @@ invoker_mark(Invoker *invoker)
785
796
  if (invoker->callbackCount > 0) {
786
797
  rb_gc_mark_locations(&invoker->callbackParameters[0], &invoker->callbackParameters[invoker->callbackCount]);
787
798
  }
788
- if (invoker->library != Qnil) {
789
- rb_gc_mark(invoker->library);
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);
790
807
  }
791
808
  }
792
809
 
@@ -840,11 +857,12 @@ variadic_invoker_call(VALUE self, VALUE parameterTypes, VALUE parameterValues)
840
857
 
841
858
  for (i = 0; i < paramCount; ++i) {
842
859
  VALUE entry = rb_ary_entry(parameterTypes, i);
843
- int paramType = FIX2INT(entry);
860
+ int paramType = rbffi_Type_GetIntValue(entry);
844
861
  switch (paramType) {
845
862
  case NATIVE_INT8:
846
863
  case NATIVE_INT16:
847
864
  case NATIVE_INT32:
865
+ case NATIVE_ENUM:
848
866
  paramType = NATIVE_INT32;
849
867
  break;
850
868
  case NATIVE_UINT8:
@@ -857,14 +875,14 @@ variadic_invoker_call(VALUE self, VALUE parameterTypes, VALUE parameterValues)
857
875
  break;
858
876
  }
859
877
  paramTypes[i] = paramType;
860
- ffiParamTypes[i] = rb_FFI_NativeTypeToFFI(paramType);
878
+ ffiParamTypes[i] = rbffi_NativeType_ToFFI(paramType);
861
879
  if (ffiParamTypes[i] == NULL) {
862
880
  rb_raise(rb_eArgError, "Invalid parameter type #%x", paramType);
863
881
  }
864
882
  argv[i] = rb_ary_entry(parameterValues, i);
865
883
  }
866
884
 
867
- ffiReturnType = rb_FFI_NativeTypeToFFI(invoker->returnType);
885
+ ffiReturnType = invoker->returnType->ffiType;
868
886
  if (ffiReturnType == NULL) {
869
887
  rb_raise(rb_eArgError, "Invalid return type");
870
888
  }
@@ -880,7 +898,7 @@ variadic_invoker_call(VALUE self, VALUE parameterTypes, VALUE parameterValues)
880
898
  rb_raise(rb_eArgError, "Unknown FFI error");
881
899
  }
882
900
  ffi_arg_setup(invoker, paramCount, argv, paramTypes, params, ffiValues);
883
- return ffi_invoke(&cif, invoker->function, invoker->returnType, ffiValues);
901
+ return ffi_invoke(&cif, invoker, ffiValues);
884
902
  }
885
903
 
886
904
  static void*
@@ -890,94 +908,39 @@ callback_param(VALUE proc, VALUE cbInfo)
890
908
  if (proc == Qnil) {
891
909
  return NULL ;
892
910
  }
893
- callback = rb_FFI_NativeCallback_for_proc(proc, cbInfo);
911
+ callback = rbffi_NativeCallback_ForProc(proc, cbInfo);
894
912
  return ((NativeCallback *) DATA_PTR(callback))->code;
895
913
  }
896
914
 
897
- #if defined(USE_PTHREAD_LOCAL)
898
- static ThreadData*
899
- thread_data_init()
900
- {
901
- ThreadData* td = ALLOC_N(ThreadData, 1);
902
- memset(td, 0, sizeof(*td));
903
- pthread_setspecific(threadDataKey, td);
904
- return td;
905
- }
906
-
907
- static inline ThreadData*
908
- thread_data_get()
909
- {
910
- ThreadData* td = pthread_getspecific(threadDataKey);
911
- return td != NULL ? td : thread_data_init();
912
- }
913
-
914
- static void
915
- thread_data_free(void *ptr)
916
- {
917
- xfree(ptr);
918
- }
919
-
920
- #else
921
- static ID thread_data_id;
922
-
923
- static ThreadData*
924
- thread_data_init()
925
- {
926
- ThreadData* td;
927
- VALUE obj;
928
- obj = Data_Make_Struct(rb_cObject, ThreadData, NULL, -1, td);
929
- rb_thread_local_aset(rb_thread_current(), thread_data_id, obj);
930
- return td;
931
- }
932
-
933
- static inline ThreadData*
934
- thread_data_get()
935
- {
936
- VALUE obj = rb_thread_local_aref(rb_thread_current(), thread_data_id);
937
-
938
- if (obj != Qnil && TYPE(obj) == T_DATA) {
939
- return (ThreadData *) DATA_PTR(obj);
940
- }
941
- return thread_data_init();
942
- }
943
-
944
- #endif
945
- static VALUE
946
- get_last_error(VALUE self)
947
- {
948
- return INT2NUM(threadData->td_errno);
949
- }
950
- static VALUE
951
- set_last_error(VALUE self, VALUE error)
952
- {
953
- return Qnil;
954
- }
955
-
956
915
  void
957
- rb_FFI_Invoker_Init()
916
+ rbffi_Invoker_Init(VALUE moduleFFI)
958
917
  {
959
918
  ffi_type* ffiValueType;
960
919
  int i;
961
- VALUE moduleFFI = rb_define_module("FFI");
962
- VALUE moduleError = rb_define_module_under(moduleFFI, "LastError");
963
- classInvoker = rb_define_class_under(moduleFFI, "Invoker", rb_cObject);
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
+
964
925
  rb_define_alloc_func(classInvoker, invoker_allocate);
965
- rb_define_method(classInvoker, "initialize", invoker_initialize, 5);
926
+ rb_define_method(classInvoker, "initialize", invoker_initialize, 6);
966
927
  rb_define_method(classInvoker, "call", invoker_call, -1);
967
- rb_define_method(classInvoker, "call0", invoker_call0, 0);
968
- rb_define_method(classInvoker, "call1", invoker_call1, 1);
969
- rb_define_method(classInvoker, "call2", invoker_call2, 2);
970
- rb_define_method(classInvoker, "call3", invoker_call3, 3);
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");
971
932
  rb_define_method(classInvoker, "arity", invoker_arity, 0);
972
933
  rb_define_method(classInvoker, "attach", invoker_attach, 2);
973
934
  classVariadicInvoker = rb_define_class_under(moduleFFI, "VariadicInvoker", rb_cObject);
974
- rb_define_singleton_method(classVariadicInvoker, "__new", variadic_invoker_new, 4);
935
+ rb_global_variable(&classVariadicInvoker);
936
+
937
+ rb_define_singleton_method(classVariadicInvoker, "__new", variadic_invoker_new, 5);
975
938
  rb_define_method(classVariadicInvoker, "invoke", variadic_invoker_call, 2);
939
+ rb_define_alias(classVariadicInvoker, "call", "invoke");
940
+
976
941
  to_ptr = rb_intern("to_ptr");
942
+ map_symbol_id = rb_intern("__map_symbol");
977
943
 
978
- rb_define_module_function(moduleError, "error", get_last_error, 0);
979
- rb_define_module_function(moduleError, "error=", set_last_error, 1);
980
-
981
944
  ffiValueType = (sizeof (VALUE) == sizeof (long))
982
945
  ? &ffi_type_ulong : &ffi_type_uint64;
983
946
  for (i = 0; i <= MAX_FIXED_ARITY + 1; ++i) {
@@ -990,13 +953,10 @@ rb_FFI_Invoker_Init()
990
953
  #endif /* _WIN32 */
991
954
 
992
955
  #if defined(USE_PTHREAD_LOCAL)
993
- pthread_key_create(&threadDataKey, thread_data_free);
994
956
  for (i = 0; i < 4; ++i) {
995
957
  pthread_mutex_init(&methodHandlePool[i].mutex, NULL);
996
958
  }
997
959
  pthread_mutex_init(&defaultMethodHandlePool.mutex, NULL);
998
- #else
999
- thread_data_id = rb_intern("ffi_thread_local_data");
1000
960
  #endif /* USE_PTHREAD_LOCAL */
1001
961
 
1002
962
  }