ffi 0.4.0 → 0.5.0
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of ffi might be problematic. Click here for more details.
- data/README.rdoc +15 -15
- data/Rakefile +57 -8
- data/ext/ffi_c/AbstractMemory.c +101 -24
- data/ext/ffi_c/AbstractMemory.h +98 -6
- data/ext/ffi_c/ArrayType.c +129 -0
- data/ext/ffi_c/ArrayType.h +58 -0
- data/ext/ffi_c/AutoPointer.c +1 -0
- data/ext/ffi_c/Buffer.c +59 -43
- data/ext/ffi_c/Call.c +853 -0
- data/ext/ffi_c/Call.h +86 -0
- data/ext/ffi_c/ClosurePool.c +302 -0
- data/ext/ffi_c/ClosurePool.h +29 -0
- data/ext/ffi_c/DynamicLibrary.c +3 -0
- data/ext/ffi_c/Function.c +478 -0
- data/ext/ffi_c/Function.h +80 -0
- data/ext/ffi_c/FunctionInfo.c +221 -0
- data/ext/ffi_c/LastError.c +30 -6
- data/ext/ffi_c/MemoryPointer.c +50 -28
- data/ext/ffi_c/MethodHandle.c +346 -0
- data/ext/ffi_c/MethodHandle.h +53 -0
- data/ext/ffi_c/Pointer.c +73 -13
- data/ext/ffi_c/Pointer.h +31 -7
- data/ext/ffi_c/Struct.c +517 -224
- data/ext/ffi_c/Struct.h +60 -6
- data/ext/ffi_c/StructByValue.c +140 -0
- data/ext/ffi_c/StructByValue.h +53 -0
- data/ext/ffi_c/StructLayout.c +450 -0
- data/ext/ffi_c/Type.c +121 -22
- data/ext/ffi_c/Type.h +37 -8
- data/ext/ffi_c/Types.c +46 -61
- data/ext/ffi_c/Types.h +38 -7
- data/ext/ffi_c/Variadic.c +260 -0
- data/ext/ffi_c/compat.h +53 -3
- data/ext/ffi_c/extconf.rb +6 -7
- data/ext/ffi_c/ffi.c +45 -39
- data/ext/ffi_c/libffi.darwin.mk +2 -2
- data/ext/ffi_c/rbffi.h +3 -0
- data/lib/ffi/ffi.rb +7 -4
- data/lib/ffi/library.rb +34 -59
- data/lib/ffi/platform.rb +14 -4
- data/lib/ffi/struct.rb +110 -281
- data/lib/ffi/union.rb +4 -9
- data/lib/ffi/variadic.rb +1 -6
- data/spec/ffi/buffer_spec.rb +6 -0
- data/spec/ffi/callback_spec.rb +34 -3
- data/spec/ffi/function_spec.rb +73 -0
- data/spec/ffi/library_spec.rb +56 -52
- data/spec/ffi/pointer_spec.rb +3 -3
- data/spec/ffi/struct_callback_spec.rb +26 -3
- data/spec/ffi/struct_spec.rb +56 -3
- metadata +42 -11
- data/ext/ffi_c/Callback.c +0 -374
- data/ext/ffi_c/Callback.h +0 -47
- data/ext/ffi_c/Invoker.c +0 -962
- data/ext/ffi_c/NullPointer.c +0 -143
@@ -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
|
+
|
data/ext/ffi_c/AutoPointer.c
CHANGED
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
|
-
|
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->
|
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
|
-
|
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
|
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", &
|
58
|
-
p->
|
59
|
-
p->memory.size = p->
|
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 =
|
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(
|
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
|
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
|
-
|
112
|
-
}
|
121
|
+
checkBounds(&ptr->memory, offset, 1);
|
113
122
|
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
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
|
-
|
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>",
|
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->
|
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
|
-
|
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 = ¶mStorage[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
|
+
|