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