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
@@ -0,0 +1,129 @@
1
+ /*
2
+ * Copyright (c) 2009, Wayne Meissner
3
+ *
4
+ * All rights reserved.
5
+ *
6
+ * Redistribution and use in source and binary forms, with or without
7
+ * modification, are permitted provided that the following conditions are met:
8
+ *
9
+ * * Redistributions of source code must retain the above copyright notice, this
10
+ * list of conditions and the following disclaimer.
11
+ * * Redistributions in binary form must reproduce the above copyright notice
12
+ * this list of conditions and the following disclaimer in the documentation
13
+ * and/or other materials provided with the distribution.
14
+ * * The name of the author or authors may not be used to endorse or promote
15
+ * products derived from this software without specific prior written permission.
16
+ *
17
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
20
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
21
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
23
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
24
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
25
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27
+ */
28
+
29
+ #include <ruby.h>
30
+ #include <ffi.h>
31
+ #include "ArrayType.h"
32
+
33
+ static VALUE array_type_s_allocate(VALUE klass);
34
+ static VALUE array_type_initialize(VALUE self, VALUE rbComponentType, VALUE rbLength);
35
+ static void array_type_mark(ArrayType *);
36
+ static void array_type_free(ArrayType *);
37
+
38
+ VALUE rbffi_ArrayTypeClass = Qnil;
39
+
40
+ static VALUE
41
+ array_type_s_allocate(VALUE klass)
42
+ {
43
+ ArrayType* array;
44
+ VALUE obj;
45
+
46
+ obj = Data_Make_Struct(klass, ArrayType, array_type_mark, array_type_free, array);
47
+
48
+ array->base.nativeType = NATIVE_ARRAY;
49
+ array->base.ffiType = xcalloc(1, sizeof(*array->base.ffiType));
50
+ array->base.ffiType->type = FFI_TYPE_STRUCT;
51
+ array->base.ffiType->size = 0;
52
+ array->base.ffiType->alignment = 0;
53
+ array->rbComponentType = Qnil;
54
+
55
+ return obj;
56
+ }
57
+
58
+ static void
59
+ array_type_mark(ArrayType *array)
60
+ {
61
+ rb_gc_mark(array->rbComponentType);
62
+ }
63
+
64
+ static void
65
+ array_type_free(ArrayType *array)
66
+ {
67
+ xfree(array->base.ffiType);
68
+ xfree(array->ffiTypes);
69
+ xfree(array);
70
+ }
71
+
72
+
73
+ static VALUE
74
+ array_type_initialize(VALUE self, VALUE rbComponentType, VALUE rbLength)
75
+ {
76
+ ArrayType* array;
77
+ int i;
78
+
79
+ Data_Get_Struct(self, ArrayType, array);
80
+
81
+ array->length = NUM2UINT(rbLength);
82
+ array->rbComponentType = rbComponentType;
83
+ Data_Get_Struct(rbComponentType, Type, array->componentType);
84
+
85
+ array->ffiTypes = xcalloc(array->length + 1, sizeof(*array->ffiTypes));
86
+ array->base.ffiType->elements = array->ffiTypes;
87
+ array->base.ffiType->size = array->componentType->ffiType->size * array->length;
88
+ array->base.ffiType->alignment = array->componentType->ffiType->alignment;
89
+
90
+ for (i = 0; i < array->length; ++i) {
91
+ array->ffiTypes[i] = array->componentType->ffiType;
92
+ }
93
+
94
+ return self;
95
+ }
96
+
97
+ static VALUE
98
+ array_type_length(VALUE self)
99
+ {
100
+ ArrayType* array;
101
+
102
+ Data_Get_Struct(self, ArrayType, array);
103
+
104
+ return UINT2NUM(array->length);
105
+ }
106
+
107
+ static VALUE
108
+ array_type_element_type(VALUE self)
109
+ {
110
+ ArrayType* array;
111
+
112
+ Data_Get_Struct(self, ArrayType, array);
113
+
114
+ return array->rbComponentType;
115
+ }
116
+
117
+ void
118
+ rbffi_ArrayType_Init(VALUE moduleFFI)
119
+ {
120
+ rbffi_ArrayTypeClass = rb_define_class_under(moduleFFI, "ArrayType", rbffi_TypeClass);
121
+ rb_global_variable(&rbffi_ArrayTypeClass);
122
+ rb_define_const(rbffi_TypeClass, "Array", rbffi_ArrayTypeClass);
123
+
124
+ rb_define_alloc_func(rbffi_ArrayTypeClass, array_type_s_allocate);
125
+ rb_define_method(rbffi_ArrayTypeClass, "initialize", array_type_initialize, 2);
126
+ rb_define_method(rbffi_ArrayTypeClass, "length", array_type_length, 0);
127
+ rb_define_method(rbffi_ArrayTypeClass, "elem_type", array_type_element_type, 0);
128
+ }
129
+
@@ -0,0 +1,58 @@
1
+ /*
2
+ * Copyright (c) 2009, Wayne Meissner
3
+ *
4
+ * All rights reserved.
5
+ *
6
+ * Redistribution and use in source and binary forms, with or without
7
+ * modification, are permitted provided that the following conditions are met:
8
+ *
9
+ * * Redistributions of source code must retain the above copyright notice, this
10
+ * list of conditions and the following disclaimer.
11
+ * * Redistributions in binary form must reproduce the above copyright notice
12
+ * this list of conditions and the following disclaimer in the documentation
13
+ * and/or other materials provided with the distribution.
14
+ * * The name of the author or authors may not be used to endorse or promote
15
+ * products derived from this software without specific prior written permission.
16
+ *
17
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
20
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
21
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
23
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
24
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
25
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27
+ */
28
+
29
+ #ifndef RBFFI_ARRAYTYPE_H
30
+ #define RBFFI_ARRAYTYPE_H
31
+
32
+ #include <ruby.h>
33
+ #include <ffi.h>
34
+ #include "Type.h"
35
+
36
+ #ifdef __cplusplus
37
+ extern "C" {
38
+ #endif
39
+
40
+
41
+ typedef struct ArrayType_ {
42
+ Type base;
43
+ int length;
44
+ ffi_type** ffiTypes;
45
+ Type* componentType;
46
+ VALUE rbComponentType;
47
+ } ArrayType;
48
+
49
+ extern void rbffi_ArrayType_Init(VALUE moduleFFI);
50
+ extern VALUE rbffi_ArrayTypeClass;
51
+
52
+
53
+ #ifdef __cplusplus
54
+ }
55
+ #endif
56
+
57
+ #endif /* RBFFI_ARRAYTYPE_H */
58
+
@@ -26,6 +26,7 @@ autoptr_allocate(VALUE klass)
26
26
  VALUE obj = Data_Make_Struct(klass, AutoPointer, autoptr_mark, -1, p);
27
27
  p->parent = Qnil;
28
28
  p->memory.ops = &rbffi_AbstractMemoryOps;
29
+ p->memory.access = MEM_RD | MEM_WR;
29
30
 
30
31
  return obj;
31
32
  }
data/ext/ffi_c/Buffer.c CHANGED
@@ -1,3 +1,30 @@
1
+ /*
2
+ * Copyright (c) 2008, 2009, Wayne Meissner
3
+ * All rights reserved.
4
+ *
5
+ * Redistribution and use in source and binary forms, with or without
6
+ * modification, are permitted provided that the following conditions are met:
7
+ *
8
+ * * Redistributions of source code must retain the above copyright notice, this
9
+ * list of conditions and the following disclaimer.
10
+ * * Redistributions in binary form must reproduce the above copyright notice
11
+ * this list of conditions and the following disclaimer in the documentation
12
+ * and/or other materials provided with the distribution.
13
+ * * The name of the author or authors may not be used to endorse or promote
14
+ * products derived from this software without specific prior written permission.
15
+ *
16
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
20
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
22
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
23
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
24
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
25
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26
+ */
27
+
1
28
  #include <stdbool.h>
2
29
  #include <stdint.h>
3
30
  #include <limits.h>
@@ -8,8 +35,7 @@
8
35
  typedef struct Buffer {
9
36
  AbstractMemory memory;
10
37
  char* storage; /* start of malloc area */
11
- int type_size;
12
- VALUE parent;
38
+ VALUE rbParent;
13
39
  } Buffer;
14
40
 
15
41
  static VALUE buffer_allocate(VALUE klass);
@@ -19,7 +45,6 @@ static void buffer_mark(Buffer* ptr);
19
45
  static VALUE buffer_free(VALUE self);
20
46
 
21
47
  static VALUE BufferClass = Qnil;
22
- #define BUFFER(obj) ((Buffer *) rbffi_AbstractMemory_Cast((obj), BufferClass))
23
48
 
24
49
  static VALUE
25
50
  buffer_allocate(VALUE klass)
@@ -28,8 +53,9 @@ buffer_allocate(VALUE klass)
28
53
  VALUE obj;
29
54
 
30
55
  obj = Data_Make_Struct(klass, Buffer, NULL, buffer_release, buffer);
31
- buffer->parent = Qnil;
56
+ buffer->rbParent = Qnil;
32
57
  buffer->memory.ops = &rbffi_AbstractMemoryOps;
58
+ buffer->memory.access = MEM_RD | MEM_WR;
33
59
 
34
60
  return obj;
35
61
  }
@@ -38,7 +64,7 @@ static void
38
64
  buffer_release(Buffer* ptr)
39
65
  {
40
66
  if (ptr->storage != NULL) {
41
- free(ptr->storage);
67
+ xfree(ptr->storage);
42
68
  ptr->storage = NULL;
43
69
  }
44
70
 
@@ -48,17 +74,17 @@ buffer_release(Buffer* ptr)
48
74
  static VALUE
49
75
  buffer_initialize(int argc, VALUE* argv, VALUE self)
50
76
  {
51
- VALUE size = Qnil, count = Qnil, clear = Qnil;
77
+ VALUE rbSize = Qnil, rbCount = Qnil, rbClear = Qnil;
52
78
  Buffer* p;
53
79
  int nargs;
54
80
 
55
81
  Data_Get_Struct(self, Buffer, p);
56
82
 
57
- nargs = rb_scan_args(argc, argv, "12", &size, &count, &clear);
58
- p->type_size = rbffi_type_size(size);
59
- p->memory.size = p->type_size * (nargs > 1 ? NUM2LONG(count) : 1);
83
+ nargs = rb_scan_args(argc, argv, "12", &rbSize, &rbCount, &rbClear);
84
+ p->memory.typeSize = rbffi_type_size(rbSize);
85
+ p->memory.size = p->memory.typeSize * (nargs > 1 ? NUM2LONG(rbCount) : 1);
60
86
 
61
- p->storage = malloc(p->memory.size + 7);
87
+ p->storage = xmalloc(p->memory.size + 7);
62
88
  if (p->storage == NULL) {
63
89
  rb_raise(rb_eNoMemError, "Failed to allocate memory size=%lu bytes", p->memory.size);
64
90
  }
@@ -66,7 +92,7 @@ buffer_initialize(int argc, VALUE* argv, VALUE self)
66
92
  /* ensure the memory is aligned on at least a 8 byte boundary */
67
93
  p->memory.address = (void *) (((uintptr_t) p->storage + 0x7) & (uintptr_t) ~0x7UL);
68
94
 
69
- if (nargs > 2 && (RTEST(clear) || clear == Qnil) && p->memory.size > 0) {
95
+ if (nargs > 2 && (RTEST(rbClear) || rbClear == Qnil) && p->memory.size > 0) {
70
96
  memset(p->memory.address, 0, p->memory.size);
71
97
  }
72
98
 
@@ -84,48 +110,36 @@ buffer_alloc_inout(int argc, VALUE* argv, VALUE klass)
84
110
  }
85
111
 
86
112
  static VALUE
87
- buffer_plus(VALUE self, VALUE offset)
88
- {
89
- Buffer* ptr = BUFFER(self);
90
- Buffer* p;
91
- VALUE retval;
92
- long off = NUM2LONG(offset);
93
-
94
- checkBounds(&ptr->memory, off, 1);
95
-
96
- retval = Data_Make_Struct(BufferClass, Buffer, buffer_mark, -1, p);
97
- p->memory.address = ptr->memory.address + off;
98
- p->memory.size = ptr->memory.size - off;
99
- p->memory.ops = &rbffi_AbstractMemoryOps;
100
- p->parent = self;
101
-
102
- return retval;
103
- }
104
-
105
- static VALUE
106
- buffer_aref(VALUE self, VALUE offset)
113
+ buffer_plus(VALUE self, VALUE rbOffset)
107
114
  {
108
115
  Buffer* ptr;
116
+ Buffer* result;
117
+ VALUE obj = Qnil;
118
+ long offset = NUM2LONG(rbOffset);
109
119
 
110
120
  Data_Get_Struct(self, Buffer, ptr);
111
- return buffer_plus(self, INT2FIX(ptr->type_size * NUM2INT(offset)));
112
- }
121
+ checkBounds(&ptr->memory, offset, 1);
113
122
 
114
- static VALUE
115
- buffer_type_size(VALUE self)
116
- {
117
- Buffer* ptr;
123
+ obj = Data_Make_Struct(BufferClass, Buffer, buffer_mark, -1, result);
124
+ result->memory.address = ptr->memory.address + offset;
125
+ result->memory.size = ptr->memory.size - offset;
126
+ result->memory.ops = ptr->memory.ops;
127
+ result->memory.access = ptr->memory.access;
128
+ result->memory.typeSize = ptr->memory.typeSize;
129
+ result->rbParent = self;
118
130
 
119
- Data_Get_Struct(self, Buffer, ptr);
120
- return INT2NUM(ptr->type_size);
131
+ return obj;
121
132
  }
122
133
 
123
134
  static VALUE
124
135
  buffer_inspect(VALUE self)
125
136
  {
126
137
  char tmp[100];
138
+ Buffer* ptr;
139
+
140
+ Data_Get_Struct(self, Buffer, ptr);
127
141
 
128
- snprintf(tmp, sizeof(tmp), "#<Buffer size=%ld>", BUFFER(self)->memory.size);
142
+ snprintf(tmp, sizeof(tmp), "#<FFI:Buffer:%p address=%p size=%ld>", ptr, ptr->memory.address, ptr->memory.size);
129
143
 
130
144
  return rb_str_new2(tmp);
131
145
  }
@@ -148,7 +162,7 @@ buffer_free(VALUE self)
148
162
  static void
149
163
  buffer_mark(Buffer* ptr)
150
164
  {
151
- rb_gc_mark(ptr->parent);
165
+ rb_gc_mark(ptr->rbParent);
152
166
  }
153
167
 
154
168
  void
@@ -162,10 +176,12 @@ rbffi_Buffer_Init(VALUE moduleFFI)
162
176
  rb_define_singleton_method(BufferClass, "alloc_inout", buffer_alloc_inout, -1);
163
177
  rb_define_singleton_method(BufferClass, "alloc_out", buffer_alloc_inout, -1);
164
178
  rb_define_singleton_method(BufferClass, "alloc_in", buffer_alloc_inout, -1);
179
+ rb_define_alias(rb_singleton_class(BufferClass), "new_in", "alloc_in");
180
+ rb_define_alias(rb_singleton_class(BufferClass), "new_out", "alloc_out");
181
+ rb_define_alias(rb_singleton_class(BufferClass), "new_inout", "alloc_inout");
165
182
 
166
183
  rb_define_method(BufferClass, "initialize", buffer_initialize, -1);
167
184
  rb_define_method(BufferClass, "inspect", buffer_inspect, 0);
168
- rb_define_method(BufferClass, "type_size", buffer_type_size, 0);
169
- rb_define_method(BufferClass, "[]", buffer_aref, 1);
185
+ rb_define_alias(BufferClass, "length", "total");
170
186
  rb_define_method(BufferClass, "+", buffer_plus, 1);
171
187
  }
data/ext/ffi_c/Call.c ADDED
@@ -0,0 +1,853 @@
1
+ /*
2
+ * Copyright (c) 2009, Wayne Meissner
3
+ * Copyright (c) 2009, Luc Heinrich <luc@honk-honk.com>
4
+ * Copyright (c) 2009, Mike Dalessio <mike.dalessio@gmail.com>
5
+ * Copyright (c) 2009, Aman Gupta.
6
+ * All rights reserved.
7
+ *
8
+ * Redistribution and use in source and binary forms, with or without
9
+ * modification, are permitted provided that the following conditions are met:
10
+ *
11
+ * * Redistributions of source code must retain the above copyright notice, this
12
+ * list of conditions and the following disclaimer.
13
+ * * Redistributions in binary form must reproduce the above copyright notice
14
+ * this list of conditions and the following disclaimer in the documentation
15
+ * and/or other materials provided with the distribution.
16
+ * * The name of the author or authors may not be used to endorse or promote
17
+ * products derived from this software without specific prior written permission.
18
+ *
19
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
20
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
22
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
23
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
25
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
26
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
27
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29
+ */
30
+
31
+ #include <sys/param.h>
32
+ #include <sys/types.h>
33
+ #include <stdio.h>
34
+ #include <stdint.h>
35
+ #include <stdbool.h>
36
+ #include <errno.h>
37
+ #include <ruby.h>
38
+ #if defined(HAVE_NATIVETHREAD) && defined(HAVE_RB_THREAD_BLOCKING_REGION) && !defined(_WIN32)
39
+ # include <signal.h>
40
+ # include <pthread.h>
41
+ #endif
42
+ #include <ffi.h>
43
+ #include "extconf.h"
44
+ #include "rbffi.h"
45
+ #include "compat.h"
46
+ #include "AbstractMemory.h"
47
+ #include "Pointer.h"
48
+ #include "Struct.h"
49
+ #include "Function.h"
50
+ #include "Type.h"
51
+ #include "LastError.h"
52
+ #include "Call.h"
53
+
54
+ #ifdef USE_RAW
55
+ # ifndef __i386__
56
+ # error "RAW argument packing only supported on i386"
57
+ # endif
58
+
59
+ #define INT8_ADJ (4)
60
+ #define INT16_ADJ (4)
61
+ #define INT32_ADJ (4)
62
+ #define INT64_ADJ (8)
63
+ #define FLOAT32_ADJ (4)
64
+ #define FLOAT64_ADJ (8)
65
+ #define ADDRESS_ADJ (sizeof(void *))
66
+
67
+ #endif /* USE_RAW */
68
+
69
+ #ifdef USE_RAW
70
+ # define ADJ(p, a) ((p) = (FFIStorage*) (((char *) p) + a##_ADJ))
71
+ #else
72
+ # define ADJ(p, a) (++(p))
73
+ #endif
74
+
75
+ static void* callback_param(VALUE proc, VALUE cbinfo);
76
+ static inline int getSignedInt(VALUE value, int type, int minValue, int maxValue, const char* typeName, VALUE enums);
77
+ static inline int getUnsignedInt(VALUE value, int type, int maxValue, const char* typeName);
78
+ static inline unsigned int getUnsignedInt32(VALUE value, int type);
79
+ static inline void* getPointer(VALUE value, int type);
80
+ static inline char* getString(VALUE value, int type);
81
+
82
+
83
+ #ifdef BYPASS_FFI
84
+ static long rbffi_GetLongValue(int idx, VALUE* argv, FunctionType* fnInfo);
85
+ static VALUE rbffi_InvokeVrL(int argc, VALUE* argv, void* function, FunctionType* fnInfo);
86
+ static VALUE rbffi_InvokeLrL(int argc, VALUE* argv, void* function, FunctionType* fnInfo);
87
+ static VALUE rbffi_InvokeLLrL(int argc, VALUE* argv, void* function, FunctionType* fnInfo);
88
+ static VALUE rbffi_InvokeLLLrL(int argc, VALUE* argv, void* function, FunctionType* fnInfo);
89
+ static VALUE rbffi_InvokeLLLLrL(int argc, VALUE* argv, void* function, FunctionType* fnInfo);
90
+ static VALUE rbffi_InvokeLLLLLrL(int argc, VALUE* argv, void* function, FunctionType* fnInfo);
91
+ static VALUE rbffi_InvokeLLLLLLrL(int argc, VALUE* argv, void* function, FunctionType* fnInfo);
92
+ static VALUE rbffi_InvokeLongParams(int argc, VALUE* argv, void* function, FunctionType* fnInfo);
93
+ #endif
94
+
95
+
96
+ static ID id_to_ptr, id_map_symbol;
97
+
98
+ void
99
+ rbffi_SetupCallParams(int argc, VALUE* argv, int paramCount, NativeType* paramTypes,
100
+ FFIStorage* paramStorage, void** ffiValues,
101
+ VALUE* callbackParameters, int callbackCount, VALUE enums)
102
+ {
103
+ VALUE callbackProc = Qnil;
104
+ FFIStorage* param = &paramStorage[0];
105
+ int i, argidx, cbidx, argCount;
106
+
107
+ if (paramCount != -1 && paramCount != argc) {
108
+ if (argc == (paramCount - 1) && callbackCount == 1 && rb_block_given_p()) {
109
+ callbackProc = rb_block_proc();
110
+ } else {
111
+ rb_raise(rb_eArgError, "wrong number of arguments (%d for %d)", argc, paramCount);
112
+ }
113
+ }
114
+
115
+ argCount = paramCount != -1 ? paramCount : argc;
116
+
117
+ for (i = 0, argidx = 0, cbidx = 0; i < argCount; ++i) {
118
+ int type = argidx < argc ? TYPE(argv[argidx]) : T_NONE;
119
+ ffiValues[i] = param;
120
+
121
+ switch (paramTypes[i]) {
122
+
123
+ case NATIVE_INT8:
124
+ param->s8 = getSignedInt(argv[argidx++], type, -128, 127, "char", Qnil);
125
+ ADJ(param, INT8);
126
+ break;
127
+
128
+
129
+ case NATIVE_INT16:
130
+ param->s16 = getSignedInt(argv[argidx++], type, -0x8000, 0x7fff, "short", Qnil);
131
+ ADJ(param, INT16);
132
+ break;
133
+
134
+
135
+ case NATIVE_INT32:
136
+ case NATIVE_ENUM:
137
+ param->s32 = getSignedInt(argv[argidx++], type, -0x80000000, 0x7fffffff, "int", enums);
138
+ ADJ(param, INT32);
139
+ break;
140
+
141
+
142
+ case NATIVE_BOOL:
143
+ if (type != T_TRUE && type != T_FALSE) {
144
+ rb_raise(rb_eTypeError, "Expected a Boolean parameter");
145
+ }
146
+ param->s32 = argv[argidx++] == Qtrue;
147
+ ADJ(param, INT32);
148
+ break;
149
+
150
+
151
+ case NATIVE_UINT8:
152
+ param->u8 = getUnsignedInt(argv[argidx++], type, 0xff, "unsigned char");
153
+ ADJ(param, INT8);
154
+ break;
155
+
156
+
157
+ case NATIVE_UINT16:
158
+ param->u16 = getUnsignedInt(argv[argidx++], type, 0xffff, "unsigned short");
159
+ ADJ(param, INT16);
160
+ break;
161
+
162
+
163
+ case NATIVE_UINT32:
164
+ /* Special handling/checking for unsigned 32 bit integers */
165
+ param->u32 = getUnsignedInt32(argv[argidx++], type);
166
+ ADJ(param, INT32);
167
+ break;
168
+
169
+
170
+ case NATIVE_INT64:
171
+ if (type != T_FIXNUM && type != T_BIGNUM) {
172
+ rb_raise(rb_eTypeError, "Expected an Integer parameter");
173
+ }
174
+ param->i64 = NUM2LL(argv[argidx]);
175
+ ADJ(param, INT64);
176
+ ++argidx;
177
+ break;
178
+
179
+
180
+ case NATIVE_UINT64:
181
+ if (type != T_FIXNUM && type != T_BIGNUM) {
182
+ rb_raise(rb_eTypeError, "Expected an Integer parameter");
183
+ }
184
+ param->u64 = NUM2ULL(argv[argidx]);
185
+ ADJ(param, INT64);
186
+ ++argidx;
187
+ break;
188
+
189
+
190
+ case NATIVE_FLOAT32:
191
+ if (type != T_FLOAT && type != T_FIXNUM) {
192
+ rb_raise(rb_eTypeError, "Expected a Float parameter");
193
+ }
194
+ param->f32 = (float) NUM2DBL(argv[argidx]);
195
+ ADJ(param, FLOAT32);
196
+ ++argidx;
197
+ break;
198
+
199
+ case NATIVE_FLOAT64:
200
+ if (type != T_FLOAT && type != T_FIXNUM) {
201
+ rb_raise(rb_eTypeError, "Expected a Float parameter");
202
+ }
203
+ param->f64 = NUM2DBL(argv[argidx]);
204
+ ADJ(param, FLOAT64);
205
+ ++argidx;
206
+ break;
207
+
208
+
209
+ case NATIVE_STRING:
210
+ param->ptr = getString(argv[argidx++], type);
211
+ ADJ(param, ADDRESS);
212
+ break;
213
+
214
+ case NATIVE_POINTER:
215
+ case NATIVE_BUFFER_IN:
216
+ case NATIVE_BUFFER_OUT:
217
+ case NATIVE_BUFFER_INOUT:
218
+ param->ptr = getPointer(argv[argidx++], type);
219
+ ADJ(param, ADDRESS);
220
+ break;
221
+
222
+
223
+ case NATIVE_FUNCTION:
224
+ case NATIVE_CALLBACK:
225
+ if (callbackProc != Qnil) {
226
+ param->ptr = callback_param(callbackProc, callbackParameters[cbidx++]);
227
+ } else {
228
+ param->ptr = callback_param(argv[argidx], callbackParameters[cbidx++]);
229
+ ++argidx;
230
+ }
231
+ ADJ(param, ADDRESS);
232
+ break;
233
+
234
+ case NATIVE_STRUCT:
235
+ ffiValues[i] = getPointer(argv[argidx++], type);
236
+ break;
237
+
238
+ default:
239
+ rb_raise(rb_eArgError, "Invalid parameter type: %d", paramTypes[i]);
240
+ }
241
+ }
242
+ }
243
+
244
+
245
+ #if defined(HAVE_NATIVETHREAD) && defined(HAVE_RB_THREAD_BLOCKING_REGION)
246
+
247
+ typedef struct BlockingCall_ {
248
+ void* function;
249
+ FunctionType* info;
250
+ void **ffiValues;
251
+ FFIStorage* retval;
252
+ } BlockingCall;
253
+
254
+ static VALUE
255
+ call_blocking_function(void* data)
256
+ {
257
+ BlockingCall* b = (BlockingCall *) data;
258
+
259
+ ffi_call(&b->info->ffi_cif, FFI_FN(b->function), b->retval, b->ffiValues);
260
+
261
+ return Qnil;
262
+ }
263
+ #endif
264
+
265
+ VALUE
266
+ rbffi_CallFunction(int argc, VALUE* argv, void* function, FunctionType* fnInfo)
267
+ {
268
+ void* retval;
269
+ void** ffiValues;
270
+ FFIStorage* params;
271
+
272
+ ffiValues = ALLOCA_N(void *, fnInfo->parameterCount);
273
+ params = ALLOCA_N(FFIStorage, fnInfo->parameterCount);
274
+ retval = alloca(MAX(fnInfo->ffi_cif.rtype->size, FFI_SIZEOF_ARG));
275
+
276
+ rbffi_SetupCallParams(argc, argv,
277
+ fnInfo->parameterCount, fnInfo->nativeParameterTypes, params, ffiValues,
278
+ fnInfo->callbackParameters, fnInfo->callbackCount, fnInfo->rbEnums);
279
+
280
+ #if defined(HAVE_NATIVETHREAD) && defined(HAVE_RB_THREAD_BLOCKING_REGION)
281
+ if (unlikely(fnInfo->blocking)) {
282
+ BlockingCall bc;
283
+
284
+ bc.info = fnInfo;
285
+ bc.function = function;
286
+ bc.ffiValues = ffiValues;
287
+ bc.retval = retval;
288
+
289
+ rb_thread_blocking_region(call_blocking_function, &bc, (void *) -1, NULL);
290
+ } else {
291
+ ffi_call(&fnInfo->ffi_cif, FFI_FN(function), retval, ffiValues);
292
+ }
293
+ #else
294
+ ffi_call(&fnInfo->ffi_cif, FFI_FN(function), retval, ffiValues);
295
+ #endif
296
+
297
+ if (!fnInfo->ignoreErrno) {
298
+ rbffi_save_errno();
299
+ }
300
+
301
+ return rbffi_NativeValue_ToRuby(fnInfo->returnType, fnInfo->rbReturnType, retval,
302
+ fnInfo->rbEnums);
303
+ }
304
+
305
+ static inline int
306
+ getSignedInt(VALUE value, int type, int minValue, int maxValue, const char* typeName, VALUE enums)
307
+ {
308
+ int i;
309
+
310
+ if (type == T_SYMBOL && enums != Qnil) {
311
+ value = rb_funcall2(enums, id_map_symbol, 1, &value);
312
+ if (value == Qnil) {
313
+ rb_raise(rb_eTypeError, "Expected a valid enum constant");
314
+ }
315
+
316
+ } else if (type != T_FIXNUM && type != T_BIGNUM) {
317
+ rb_raise(rb_eTypeError, "Expected an Integer parameter");
318
+ }
319
+
320
+ i = NUM2INT(value);
321
+ if (i < minValue || i > maxValue) {
322
+ rb_raise(rb_eRangeError, "Value %d outside %s range", i, typeName);
323
+ }
324
+
325
+ return i;
326
+ }
327
+
328
+ static inline int
329
+ getUnsignedInt(VALUE value, int type, int maxValue, const char* typeName)
330
+ {
331
+ int i;
332
+
333
+ if (type != T_FIXNUM && type != T_BIGNUM) {
334
+ rb_raise(rb_eTypeError, "Expected an Integer parameter");
335
+ }
336
+
337
+ i = NUM2INT(value);
338
+ if (i < 0 || i > maxValue) {
339
+ rb_raise(rb_eRangeError, "Value %d outside %s range", i, typeName);
340
+ }
341
+
342
+ return i;
343
+ }
344
+
345
+ /* Special handling/checking for unsigned 32 bit integers */
346
+ static inline unsigned int
347
+ getUnsignedInt32(VALUE value, int type)
348
+ {
349
+ long long i;
350
+
351
+ if (type != T_FIXNUM && type != T_BIGNUM) {
352
+ rb_raise(rb_eTypeError, "Expected an Integer parameter");
353
+ }
354
+
355
+ i = NUM2LL(value);
356
+ if (i < 0L || i > 0xffffffffL) {
357
+ rb_raise(rb_eRangeError, "Value %lld outside unsigned int range", i);
358
+ }
359
+
360
+ return (unsigned int) i;
361
+ }
362
+
363
+ static inline void*
364
+ getPointer(VALUE value, int type)
365
+ {
366
+ if (type == T_DATA && rb_obj_is_kind_of(value, rbffi_AbstractMemoryClass)) {
367
+
368
+ return ((AbstractMemory *) DATA_PTR(value))->address;
369
+
370
+ } else if (type == T_DATA && rb_obj_is_kind_of(value, rbffi_StructClass)) {
371
+
372
+ AbstractMemory* memory = ((Struct *) DATA_PTR(value))->pointer;
373
+ return memory != NULL ? memory->address : NULL;
374
+
375
+ } else if (type == T_STRING) {
376
+
377
+ if (rb_safe_level() >= 1 && OBJ_TAINTED(value)) {
378
+ rb_raise(rb_eSecurityError, "Unsafe string parameter");
379
+ }
380
+ return StringValuePtr(value);
381
+
382
+ } else if (type == T_NIL) {
383
+
384
+ return NULL;
385
+
386
+ } else if (rb_respond_to(value, id_to_ptr)) {
387
+
388
+ VALUE ptr = rb_funcall2(value, id_to_ptr, 0, NULL);
389
+ if (rb_obj_is_kind_of(ptr, rbffi_AbstractMemoryClass) && TYPE(ptr) == T_DATA) {
390
+ return ((AbstractMemory *) DATA_PTR(ptr))->address;
391
+ }
392
+ rb_raise(rb_eArgError, "to_ptr returned an invalid pointer");
393
+ }
394
+
395
+ rb_raise(rb_eArgError, ":pointer argument is not a valid pointer");
396
+ return NULL;
397
+ }
398
+
399
+ static inline char*
400
+ getString(VALUE value, int type)
401
+ {
402
+ if (type == T_STRING) {
403
+
404
+ if (rb_safe_level() >= 1 && OBJ_TAINTED(value)) {
405
+ rb_raise(rb_eSecurityError, "Unsafe string parameter");
406
+ }
407
+
408
+ return StringValueCStr(value);
409
+
410
+ } else if (type == T_NIL) {
411
+ return NULL;
412
+ }
413
+
414
+ rb_raise(rb_eArgError, "Invalid String value");
415
+ }
416
+
417
+
418
+ Invoker
419
+ rbffi_GetInvoker(FunctionType *fnInfo)
420
+ {
421
+ #if defined(BYPASS_FFI) && (defined(__i386__) || defined(__x86_64__))
422
+ int i;
423
+ bool fastLong = fnInfo->abi == FFI_DEFAULT_ABI && !fnInfo->blocking && !fnInfo->hasStruct;
424
+
425
+ switch (fnInfo->returnType->nativeType) {
426
+ case NATIVE_VOID:
427
+ case NATIVE_BOOL:
428
+ case NATIVE_INT8:
429
+ case NATIVE_UINT8:
430
+ case NATIVE_INT16:
431
+ case NATIVE_UINT16:
432
+ case NATIVE_INT32:
433
+ case NATIVE_UINT32:
434
+ #ifdef __x86_64__
435
+ case NATIVE_INT64:
436
+ case NATIVE_UINT64:
437
+ #endif
438
+ case NATIVE_STRING:
439
+ case NATIVE_POINTER:
440
+ break;
441
+ default:
442
+ fastLong = false;
443
+ break;
444
+ }
445
+
446
+ for (i = 0; fastLong && i < fnInfo->parameterCount; ++i) {
447
+ switch (fnInfo->nativeParameterTypes[i]) {
448
+ case NATIVE_BOOL:
449
+ case NATIVE_INT8:
450
+ case NATIVE_UINT8:
451
+ case NATIVE_INT16:
452
+ case NATIVE_UINT16:
453
+ case NATIVE_INT32:
454
+ case NATIVE_UINT32:
455
+ #ifdef __x86_64__
456
+ case NATIVE_INT64:
457
+ case NATIVE_UINT64:
458
+ #endif
459
+ case NATIVE_STRING:
460
+ case NATIVE_POINTER:
461
+ case NATIVE_BUFFER_IN:
462
+ case NATIVE_BUFFER_OUT:
463
+ case NATIVE_BUFFER_INOUT:
464
+ case NATIVE_FUNCTION:
465
+ case NATIVE_CALLBACK:
466
+ break;
467
+ default:
468
+ fastLong = false;
469
+ break;
470
+ }
471
+ }
472
+
473
+ if (fastLong && fnInfo->callbackCount < 1) {
474
+ switch (fnInfo->parameterCount) {
475
+ case 0:
476
+ return rbffi_InvokeVrL;
477
+ case 1:
478
+ return rbffi_InvokeLrL;
479
+ case 2:
480
+ return rbffi_InvokeLLrL;
481
+ case 3:
482
+ return rbffi_InvokeLLLrL;
483
+ case 4:
484
+ return rbffi_InvokeLLLLrL;
485
+ case 5:
486
+ return rbffi_InvokeLLLLLrL;
487
+ case 6:
488
+ return rbffi_InvokeLLLLLLrL;
489
+
490
+ default:
491
+ break;
492
+ }
493
+
494
+ } else if (fastLong && fnInfo->parameterCount <= 6) {
495
+ return rbffi_InvokeLongParams;
496
+ }
497
+ #endif
498
+
499
+ return rbffi_CallFunction;
500
+ }
501
+
502
+ #if defined(BYPASS_FFI) && (defined(__i386__) || defined(__x86_64__))
503
+ typedef long L;
504
+
505
+ static long
506
+ rbffi_GetLongValue(int idx, VALUE* argv, FunctionType* fnInfo)
507
+ {
508
+ VALUE value = argv[idx];
509
+ NativeType nativeType = fnInfo->nativeParameterTypes[idx];
510
+ int type = TYPE(value);
511
+
512
+ switch (nativeType) {
513
+ case NATIVE_INT8:
514
+ return getSignedInt(value, type, -128, 127, "char", fnInfo->rbEnums);
515
+
516
+ case NATIVE_INT16:
517
+ return getSignedInt(value, type, -0x8000, 0x7fff, "short", fnInfo->rbEnums);
518
+
519
+ case NATIVE_INT32:
520
+ case NATIVE_ENUM:
521
+ return getSignedInt(value, type, -0x80000000, 0x7fffffff, "int", fnInfo->rbEnums);
522
+
523
+ case NATIVE_BOOL:
524
+ if (type != T_TRUE && type != T_FALSE) {
525
+ rb_raise(rb_eTypeError, "Expected a Boolean parameter");
526
+ }
527
+ return RTEST(value) ? 1 : 0;
528
+
529
+ case NATIVE_UINT8:
530
+ return getUnsignedInt(value, type, 0xff, "unsigned char");
531
+
532
+ case NATIVE_UINT16:
533
+ return getUnsignedInt(value, type, 0xffff, "unsigned short");
534
+
535
+ case NATIVE_UINT32:
536
+ /* Special handling/checking for unsigned 32 bit integers */
537
+ return getUnsignedInt32(value, type);
538
+
539
+ #ifdef __x86_64__
540
+ case NATIVE_INT64:
541
+ if (type != T_FIXNUM && type != T_BIGNUM) {
542
+ rb_raise(rb_eTypeError, "Expected an Integer parameter");
543
+ }
544
+ return NUM2LL(value);
545
+
546
+ case NATIVE_UINT64:
547
+ if (type != T_FIXNUM && type != T_BIGNUM) {
548
+ rb_raise(rb_eTypeError, "Expected an Integer parameter");
549
+ }
550
+ return NUM2ULL(value);
551
+ #endif
552
+ case NATIVE_STRING:
553
+ return (intptr_t) getString(value, type);
554
+
555
+ case NATIVE_POINTER:
556
+ case NATIVE_BUFFER_IN:
557
+ case NATIVE_BUFFER_OUT:
558
+ case NATIVE_BUFFER_INOUT:
559
+ return (intptr_t) getPointer(value, type);
560
+
561
+ default:
562
+ rb_raise(rb_eTypeError, "unsupported integer type %d", nativeType);
563
+ return 0;
564
+ }
565
+ }
566
+
567
+ static inline void
568
+ checkArity(int argc, int arity) {
569
+ if (unlikely(argc != arity)) {
570
+ rb_raise(rb_eArgError, "wrong number of arguments (%d for %d)", argc, arity);
571
+ }
572
+ }
573
+
574
+ static inline bool
575
+ isLongValue(VALUE value)
576
+ {
577
+ int type = TYPE(value);
578
+
579
+ return type == T_FIXNUM || type == T_BIGNUM
580
+ || type == T_STRING || type == T_NIL
581
+ || (type == T_DATA && rb_obj_is_kind_of(value, rbffi_AbstractMemoryClass))
582
+ || (type == T_DATA && rb_obj_is_kind_of(value, rbffi_StructClass))
583
+ || rb_respond_to(value, id_to_ptr);
584
+ }
585
+
586
+ static VALUE
587
+ returnL(FunctionType* fnInfo, L* result)
588
+ {
589
+ if (unlikely(!fnInfo->ignoreErrno)) {
590
+ rbffi_save_errno();
591
+ }
592
+
593
+ /*
594
+ * This needs to do custom boxing of the return value, since a function
595
+ * may only fill out the lower 8, 16 or 32 bits of %al, %ah, %eax, %rax, and
596
+ * the upper part will be garbage. This will truncate the value again, then
597
+ * sign extend it.
598
+ */
599
+ switch (fnInfo->returnType->nativeType) {
600
+ case NATIVE_VOID:
601
+ return Qnil;
602
+
603
+ case NATIVE_INT8:
604
+ return INT2NUM(*(signed char *) result);
605
+
606
+ case NATIVE_INT16:
607
+ return INT2NUM(*(signed short *) result);
608
+
609
+ case NATIVE_INT32:
610
+ return INT2NUM(*(signed int *) result);
611
+
612
+ case NATIVE_UINT8:
613
+ return UINT2NUM(*(unsigned char *) result);
614
+
615
+ case NATIVE_UINT16:
616
+ return UINT2NUM(*(unsigned short *) result);
617
+
618
+ case NATIVE_UINT32:
619
+ return UINT2NUM(*(unsigned int *) result);
620
+
621
+ #ifdef __x86_64__
622
+ case NATIVE_INT64:
623
+ return LL2NUM(*(signed long long *) result);
624
+
625
+ case NATIVE_UINT64:
626
+ return ULL2NUM(*(unsigned long long *) result);
627
+ #endif /* __x86_64__ */
628
+
629
+ case NATIVE_STRING:
630
+ return *(void **) result != 0 ? rb_tainted_str_new2(*(char **) result) : Qnil;
631
+
632
+ case NATIVE_POINTER:
633
+ return rbffi_Pointer_NewInstance(*(void **) result);
634
+
635
+ case NATIVE_BOOL:
636
+ return *(char *) result != 0 ? Qtrue : Qfalse;
637
+
638
+ default:
639
+ rb_raise(rb_eRuntimeError, "invalid return type: %d", fnInfo->returnType->nativeType);
640
+ return Qnil;
641
+ }
642
+ }
643
+
644
+ static VALUE
645
+ rbffi_InvokeVrL(int argc, VALUE* argv, void* function, FunctionType* fnInfo)
646
+ {
647
+ L (*fn)(void) = (L (*)(void)) function;
648
+ L result;
649
+
650
+ checkArity(argc, 0);
651
+
652
+ result = (*fn)();
653
+
654
+ return returnL(fnInfo, &result);
655
+ }
656
+
657
+ static bool
658
+ checkArgs(int argc, VALUE* argv, FunctionType* fnInfo)
659
+ {
660
+ int i;
661
+
662
+ checkArity(argc, fnInfo->parameterCount);
663
+ for (i = 0; i < fnInfo->parameterCount; ++i) {
664
+ if (unlikely(!isLongValue(argv[i]))) {
665
+ return false;
666
+ }
667
+ }
668
+
669
+ return true;
670
+ }
671
+
672
+ #define LARG(fnInfo, argv, i) \
673
+ rbffi_GetLongValue(i, argv, fnInfo)
674
+
675
+ #define LCALL(fnInfo, argc, argv, fn, a...) ({ \
676
+ L result; \
677
+ \
678
+ if (unlikely(!checkArgs(argc, argv, fnInfo))) { \
679
+ return rbffi_CallFunction(argc, argv, function, fnInfo); \
680
+ } \
681
+ \
682
+ result = (*(fn))(a); \
683
+ \
684
+ returnL(fnInfo, &result); \
685
+ })
686
+
687
+ static VALUE
688
+ rbffi_InvokeLrL(int argc, VALUE* argv, void* function, FunctionType* fnInfo)
689
+ {
690
+ L (*fn)(L) = (L (*)(L)) function;
691
+ L result;
692
+
693
+ checkArity(argc, 1);
694
+
695
+ if (unlikely(!isLongValue(argv[0]))) {
696
+ return rbffi_CallFunction(argc, argv, function, fnInfo);
697
+ }
698
+
699
+ result = (*fn)(LARG(fnInfo, argv, 0));
700
+
701
+ return returnL(fnInfo, &result);
702
+ }
703
+
704
+ static VALUE
705
+ rbffi_InvokeLLrL(int argc, VALUE* argv, void* function, FunctionType* fnInfo)
706
+ {
707
+ L (*fn)(L, L) = (L (*)(L, L)) function;
708
+ L result;
709
+
710
+ checkArity(argc, 2);
711
+
712
+ if (unlikely(!isLongValue(argv[0])) || unlikely(!isLongValue(argv[1]))) {
713
+ return rbffi_CallFunction(argc, argv, function, fnInfo);
714
+ }
715
+
716
+ result = (*fn)(LARG(fnInfo, argv, 0), LARG(fnInfo, argv, 1));
717
+
718
+ return returnL(fnInfo, &result);
719
+ }
720
+
721
+ static VALUE
722
+ rbffi_InvokeLLLrL(int argc, VALUE* argv, void* function, FunctionType* fnInfo)
723
+ {
724
+ L (*fn)(L, L, L) = (L (*)(L, L, L)) function;
725
+ L result;
726
+
727
+ checkArity(argc, 3);
728
+
729
+ if (unlikely(!isLongValue(argv[0])) || unlikely(!isLongValue(argv[1])) || unlikely(!isLongValue(argv[2]))) {
730
+ return rbffi_CallFunction(argc, argv, function, fnInfo);
731
+ }
732
+
733
+ result = (*fn)(LARG(fnInfo, argv, 0), LARG(fnInfo, argv, 1), LARG(fnInfo, argv, 2));
734
+
735
+ return returnL(fnInfo, &result);
736
+ }
737
+
738
+
739
+ static VALUE
740
+ rbffi_InvokeLLLLrL(int argc, VALUE* argv, void* function, FunctionType* fnInfo)
741
+ {
742
+ return LCALL(fnInfo, argc, argv, (L (*)(L, L, L, L)) function,
743
+ LARG(fnInfo, argv, 0), LARG(fnInfo, argv, 1),
744
+ LARG(fnInfo, argv, 2), LARG(fnInfo, argv, 3));
745
+ }
746
+
747
+ static VALUE
748
+ rbffi_InvokeLLLLLrL(int argc, VALUE* argv, void* function, FunctionType* fnInfo)
749
+ {
750
+ return LCALL(fnInfo, argc, argv, (L (*)(L, L, L, L, L)) function,
751
+ LARG(fnInfo, argv, 0), LARG(fnInfo, argv, 1), LARG(fnInfo, argv, 2),
752
+ LARG(fnInfo, argv, 3), LARG(fnInfo, argv, 4));
753
+ }
754
+
755
+ static VALUE
756
+ rbffi_InvokeLLLLLLrL(int argc, VALUE* argv, void* function, FunctionType* fnInfo)
757
+ {
758
+ return LCALL(fnInfo, argc, argv, (L (*)(L, L, L, L, L, L)) function,
759
+ LARG(fnInfo, argv, 0), LARG(fnInfo, argv, 1), LARG(fnInfo, argv, 2),
760
+ LARG(fnInfo, argv, 3), LARG(fnInfo, argv, 4), LARG(fnInfo, argv, 5));
761
+ }
762
+
763
+ static VALUE
764
+ rbffi_InvokeLongParams(int argc, VALUE* argv, void* function, FunctionType* fnInfo)
765
+ {
766
+ void **ffiValues = NULL;
767
+ FFIStorage* params = NULL;
768
+ L result;
769
+
770
+ if (fnInfo->parameterCount > 0) {
771
+ ffiValues = ALLOCA_N(void *, fnInfo->parameterCount);
772
+ params = ALLOCA_N(FFIStorage, fnInfo->parameterCount);
773
+
774
+ rbffi_SetupCallParams(argc, argv,
775
+ fnInfo->parameterCount, fnInfo->nativeParameterTypes, params, ffiValues,
776
+ fnInfo->callbackParameters, fnInfo->callbackCount, fnInfo->rbEnums);
777
+
778
+ switch (fnInfo->parameterCount) {
779
+ case 0:
780
+ result = ((L(*)(void)) function)();
781
+ break;
782
+
783
+ case 1:
784
+ result = ((L(*)(L)) function)(*(L *) ffiValues[0]);
785
+ break;
786
+
787
+ case 2:
788
+ result = ((L(*)(L, L)) function)(*(L *) ffiValues[0],
789
+ *(L *) ffiValues[1]);
790
+ break;
791
+
792
+ case 3:
793
+ result = ((L(*)(L, L, L)) function)(*(L *) ffiValues[0],
794
+ *(L *) ffiValues[1], *(L *) ffiValues[2]);
795
+ break;
796
+
797
+ case 4:
798
+ result = ((L(*)(L, L, L, L)) function)(*(L *) ffiValues[0],
799
+ *(L *) ffiValues[1], *(L *) ffiValues[2], *(L *) ffiValues[3]);
800
+ break;
801
+
802
+ case 5:
803
+ result = ((L(*)(L, L, L, L, L)) function)(*(L *) ffiValues[0],
804
+ *(L *) ffiValues[1], *(L *) ffiValues[2], *(L *) ffiValues[3],
805
+ *(L *) ffiValues[4]);
806
+ break;
807
+
808
+ case 6:
809
+ result = ((L(*)(L, L, L, L, L, L)) function)(*(L *) ffiValues[0],
810
+ *(L *) ffiValues[1], *(L *) ffiValues[2], *(L *) ffiValues[3],
811
+ *(L *) ffiValues[4], *(L *) ffiValues[5]);
812
+ break;
813
+
814
+ default:
815
+ rb_raise(rb_eRuntimeError, "BUG: should not reach this point");
816
+ return Qnil;
817
+ }
818
+ }
819
+
820
+ return returnL(fnInfo, &result);
821
+ }
822
+
823
+ #endif /* BYPASS_FFI */
824
+
825
+ static void*
826
+ callback_param(VALUE proc, VALUE cbInfo)
827
+ {
828
+ VALUE callback ;
829
+ if (proc == Qnil) {
830
+ return NULL ;
831
+ }
832
+
833
+ // Handle Function pointers here
834
+ if (rb_obj_is_kind_of(proc, rbffi_FunctionClass)) {
835
+ AbstractMemory* ptr;
836
+ Data_Get_Struct(proc, AbstractMemory, ptr);
837
+ return ptr->address;
838
+ }
839
+
840
+ //callback = rbffi_NativeCallback_ForProc(proc, cbInfo);
841
+ callback = rbffi_Function_ForProc(cbInfo, proc);
842
+
843
+ return ((AbstractMemory *) DATA_PTR(callback))->address;
844
+ }
845
+
846
+
847
+ void
848
+ rbffi_Call_Init(VALUE moduleFFI)
849
+ {
850
+ id_to_ptr = rb_intern("to_ptr");
851
+ id_map_symbol = rb_intern("__map_symbol");
852
+ }
853
+