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,346 @@
|
|
1
|
+
/*
|
2
|
+
* Copyright (c) 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
|
+
|
28
|
+
#include <sys/param.h>
|
29
|
+
#include <sys/types.h>
|
30
|
+
#ifndef _WIN32
|
31
|
+
# include <sys/mman.h>
|
32
|
+
#endif
|
33
|
+
#include <stdio.h>
|
34
|
+
#include <stdint.h>
|
35
|
+
#include <stdbool.h>
|
36
|
+
#ifndef _WIN32
|
37
|
+
# include <unistd.h>
|
38
|
+
#endif
|
39
|
+
#include <errno.h>
|
40
|
+
#include <ruby.h>
|
41
|
+
#if defined(HAVE_NATIVETHREAD) && !defined(_WIN32) && !defined(__WIN32__)
|
42
|
+
# include <pthread.h>
|
43
|
+
#endif
|
44
|
+
|
45
|
+
#include <ffi.h>
|
46
|
+
#include "rbffi.h"
|
47
|
+
#include "compat.h"
|
48
|
+
|
49
|
+
#include "Function.h"
|
50
|
+
#include "Types.h"
|
51
|
+
#include "Type.h"
|
52
|
+
#include "LastError.h"
|
53
|
+
#include "Call.h"
|
54
|
+
#include "ClosurePool.h"
|
55
|
+
#include "MethodHandle.h"
|
56
|
+
|
57
|
+
|
58
|
+
#define MAX_METHOD_FIXED_ARITY (6)
|
59
|
+
|
60
|
+
#if defined(HAVE_NATIVETHREAD) && !defined(_WIN32) && !defined(__WIN32__)
|
61
|
+
# define USE_PTHREAD_LOCAL
|
62
|
+
#endif
|
63
|
+
|
64
|
+
#ifndef roundup
|
65
|
+
# define roundup(x, y) ((((x)+((y)-1))/(y))*(y))
|
66
|
+
#endif
|
67
|
+
#ifdef _WIN32
|
68
|
+
typedef char* caddr_t;
|
69
|
+
#endif
|
70
|
+
|
71
|
+
#ifdef USE_RAW
|
72
|
+
# define METHOD_CLOSURE ffi_raw_closure
|
73
|
+
# define METHOD_PARAMS ffi_raw*
|
74
|
+
#else
|
75
|
+
# define METHOD_CLOSURE ffi_closure
|
76
|
+
# define METHOD_PARAMS void**
|
77
|
+
#endif
|
78
|
+
|
79
|
+
|
80
|
+
|
81
|
+
static bool prep_trampoline(void* ctx, void* code, Closure* closure, char* errmsg, size_t errmsgsize);
|
82
|
+
static int trampoline_size(void);
|
83
|
+
|
84
|
+
#if defined(__x86_64__) && defined(__GNUC__)
|
85
|
+
# define CUSTOM_TRAMPOLINE 1
|
86
|
+
#endif
|
87
|
+
|
88
|
+
|
89
|
+
struct MethodHandle {
|
90
|
+
Closure* closure;
|
91
|
+
};
|
92
|
+
|
93
|
+
static ClosurePool* defaultClosurePool;
|
94
|
+
|
95
|
+
|
96
|
+
MethodHandle*
|
97
|
+
rbffi_MethodHandle_Alloc(FunctionType* fnInfo, void* function)
|
98
|
+
{
|
99
|
+
MethodHandle* handle;
|
100
|
+
Closure* closure = rbffi_Closure_Alloc(defaultClosurePool);
|
101
|
+
if (closure == NULL) {
|
102
|
+
rb_raise(rb_eNoMemError, "failed to allocate closure from pool");
|
103
|
+
return NULL;
|
104
|
+
}
|
105
|
+
|
106
|
+
handle = xcalloc(1, sizeof(*handle));
|
107
|
+
handle->closure = closure;
|
108
|
+
closure->info = fnInfo;
|
109
|
+
closure->function = function;
|
110
|
+
|
111
|
+
return handle;
|
112
|
+
}
|
113
|
+
|
114
|
+
void
|
115
|
+
rbffi_MethodHandle_Free(MethodHandle* handle)
|
116
|
+
{
|
117
|
+
if (handle != NULL) {
|
118
|
+
rbffi_Closure_Free(handle->closure);
|
119
|
+
}
|
120
|
+
}
|
121
|
+
|
122
|
+
void*
|
123
|
+
rbffi_MethodHandle_CodeAddress(MethodHandle* handle)
|
124
|
+
{
|
125
|
+
return handle->closure->code;
|
126
|
+
}
|
127
|
+
|
128
|
+
#ifndef CUSTOM_TRAMPOLINE
|
129
|
+
static void attached_method_invoke(ffi_cif* cif, void* retval, METHOD_PARAMS parameters, void* user_data);
|
130
|
+
|
131
|
+
static ffi_type* methodHandleParamTypes[] = {
|
132
|
+
&ffi_type_sint,
|
133
|
+
&ffi_type_pointer,
|
134
|
+
&ffi_type_ulong,
|
135
|
+
};
|
136
|
+
|
137
|
+
static ffi_cif mh_cif;
|
138
|
+
|
139
|
+
static bool
|
140
|
+
prep_trampoline(void* ctx, void* code, Closure* closure, char* errmsg, size_t errmsgsize)
|
141
|
+
{
|
142
|
+
ffi_status ffiStatus;
|
143
|
+
|
144
|
+
#if defined(USE_RAW)
|
145
|
+
ffiStatus = ffi_prep_raw_closure(code, &mh_cif, attached_method_invoke, closure);
|
146
|
+
#else
|
147
|
+
ffiStatus = ffi_prep_closure(code, &mh_cif, attached_method_invoke, closure);
|
148
|
+
#endif
|
149
|
+
if (ffiStatus != FFI_OK) {
|
150
|
+
snprintf(errmsg, errmsgsize, "ffi_prep_closure failed. status=%#x", ffiStatus);
|
151
|
+
return false;
|
152
|
+
}
|
153
|
+
|
154
|
+
return true;
|
155
|
+
}
|
156
|
+
|
157
|
+
|
158
|
+
static int
|
159
|
+
trampoline_size(void)
|
160
|
+
{
|
161
|
+
return sizeof(METHOD_CLOSURE);
|
162
|
+
}
|
163
|
+
|
164
|
+
/*
|
165
|
+
* attached_method_vinvoke is used functions with more than 6 parameters, or
|
166
|
+
* with struct param or return values
|
167
|
+
*/
|
168
|
+
static void
|
169
|
+
attached_method_invoke(ffi_cif* cif, void* mretval, METHOD_PARAMS parameters, void* user_data)
|
170
|
+
{
|
171
|
+
Closure* handle = (Closure *) user_data;
|
172
|
+
FunctionType* fnInfo = (FunctionType *) handle->info;
|
173
|
+
|
174
|
+
#ifdef USE_RAW
|
175
|
+
int argc = parameters[0].sint;
|
176
|
+
VALUE* argv = *(VALUE **) ¶meters[1];
|
177
|
+
#else
|
178
|
+
int argc = *(ffi_sarg *) parameters[0];
|
179
|
+
VALUE* argv = *(VALUE **) parameters[1];
|
180
|
+
#endif
|
181
|
+
|
182
|
+
*(VALUE *) mretval = (*fnInfo->invoke)(argc, argv, handle->function, fnInfo);
|
183
|
+
}
|
184
|
+
|
185
|
+
#endif
|
186
|
+
|
187
|
+
|
188
|
+
|
189
|
+
#if defined(CUSTOM_TRAMPOLINE)
|
190
|
+
#if defined(__x86_64__)
|
191
|
+
|
192
|
+
static VALUE custom_trampoline(int argc, VALUE* argv, VALUE self, Closure*);
|
193
|
+
|
194
|
+
#define TRAMPOLINE_CTX_MAGIC (0xfee1deadcafebabe)
|
195
|
+
#define TRAMPOLINE_FUN_MAGIC (0xfeedfacebeeff00d)
|
196
|
+
|
197
|
+
/*
|
198
|
+
* This is a hand-coded trampoline to speedup entry from ruby to the FFI translation
|
199
|
+
* layer for x86_64 arches.
|
200
|
+
*
|
201
|
+
* Since a ruby function has exactly 3 arguments, and the first 6 arguments are
|
202
|
+
* passed in registers for x86_64, we can tack on a context pointer by simply
|
203
|
+
* putting a value in %rcx, then jumping to the C trampoline code.
|
204
|
+
*
|
205
|
+
* This results in approx a 30% speedup for x86_64 FFI dispatch
|
206
|
+
*/
|
207
|
+
asm(
|
208
|
+
".text\n\t"
|
209
|
+
".globl ffi_trampoline\n\t"
|
210
|
+
".globl _ffi_trampoline\n\t"
|
211
|
+
"ffi_trampoline:\n\t"
|
212
|
+
"_ffi_trampoline:\n\t"
|
213
|
+
"movabsq $0xfee1deadcafebabe, %rcx\n\t"
|
214
|
+
"movabsq $0xfeedfacebeeff00d, %r11\n\t"
|
215
|
+
"jmpq *%r11\n\t"
|
216
|
+
".globl ffi_trampoline_end\n\t"
|
217
|
+
"ffi_trampoline_end:\n\t"
|
218
|
+
".globl _ffi_trampoline_end\n\t"
|
219
|
+
"_ffi_trampoline_end:\n\t"
|
220
|
+
);
|
221
|
+
|
222
|
+
static VALUE
|
223
|
+
custom_trampoline(int argc, VALUE* argv, VALUE self, Closure* handle)
|
224
|
+
{
|
225
|
+
FunctionType* fnInfo = (FunctionType *) handle->info;
|
226
|
+
return (*fnInfo->invoke)(argc, argv, handle->function, fnInfo);
|
227
|
+
}
|
228
|
+
|
229
|
+
#elif defined(__i386__) && 0
|
230
|
+
|
231
|
+
static VALUE custom_trampoline(caddr_t args, Closure*);
|
232
|
+
#define TRAMPOLINE_CTX_MAGIC (0xfee1dead)
|
233
|
+
#define TRAMPOLINE_FUN_MAGIC (0xbeefcafe)
|
234
|
+
|
235
|
+
/*
|
236
|
+
* This is a hand-coded trampoline to speedup entry from ruby to the FFI translation
|
237
|
+
* layer for i386 arches.
|
238
|
+
*
|
239
|
+
* This does not make a discernable difference vs a raw closure, so for now,
|
240
|
+
* it is not enabled.
|
241
|
+
*/
|
242
|
+
asm(
|
243
|
+
".text\n\t"
|
244
|
+
".globl ffi_trampoline\n\t"
|
245
|
+
".globl _ffi_trampoline\n\t"
|
246
|
+
"ffi_trampoline:\n\t"
|
247
|
+
"_ffi_trampoline:\n\t"
|
248
|
+
"subl $12, %esp\n\t"
|
249
|
+
"leal 16(%esp), %eax\n\t"
|
250
|
+
"movl %eax, (%esp)\n\t"
|
251
|
+
"movl $0xfee1dead, 4(%esp)\n\t"
|
252
|
+
"movl $0xbeefcafe, %eax\n\t"
|
253
|
+
"call *%eax\n\t"
|
254
|
+
"addl $12, %esp\n\t"
|
255
|
+
"ret\n\t"
|
256
|
+
".globl ffi_trampoline_end\n\t"
|
257
|
+
"ffi_trampoline_end:\n\t"
|
258
|
+
".globl _ffi_trampoline_end\n\t"
|
259
|
+
"_ffi_trampoline_end:\n\t"
|
260
|
+
);
|
261
|
+
|
262
|
+
static VALUE
|
263
|
+
custom_trampoline(caddr_t args, Closure* handle)
|
264
|
+
{
|
265
|
+
FunctionType* fnInfo = (FunctionType *) handle->info;
|
266
|
+
return (*fnInfo->invoke)(*(int *) args, *(VALUE **) (args + 4), handle->function, fnInfo);
|
267
|
+
}
|
268
|
+
|
269
|
+
#endif /* __x86_64__ else __i386__ */
|
270
|
+
|
271
|
+
extern void ffi_trampoline(int argc, VALUE* argv, VALUE self);
|
272
|
+
extern void ffi_trampoline_end(void);
|
273
|
+
static int trampoline_offsets(int *, int *);
|
274
|
+
|
275
|
+
static int trampoline_ctx_offset, trampoline_func_offset;
|
276
|
+
|
277
|
+
static int
|
278
|
+
trampoline_offset(int off, const long value)
|
279
|
+
{
|
280
|
+
caddr_t ptr;
|
281
|
+
for (ptr = (caddr_t) &ffi_trampoline + off; ptr < (caddr_t) &ffi_trampoline_end; ++ptr) {
|
282
|
+
if (*(long *) ptr == value) {
|
283
|
+
return ptr - (caddr_t) &ffi_trampoline;
|
284
|
+
}
|
285
|
+
}
|
286
|
+
|
287
|
+
return -1;
|
288
|
+
}
|
289
|
+
|
290
|
+
static int
|
291
|
+
trampoline_offsets(int* ctxOffset, int* fnOffset)
|
292
|
+
{
|
293
|
+
*ctxOffset = trampoline_offset(0, TRAMPOLINE_CTX_MAGIC);
|
294
|
+
if (*ctxOffset == -1) {
|
295
|
+
return -1;
|
296
|
+
}
|
297
|
+
|
298
|
+
*fnOffset = trampoline_offset(0, TRAMPOLINE_FUN_MAGIC);
|
299
|
+
if (*fnOffset == -1) {
|
300
|
+
return -1;
|
301
|
+
}
|
302
|
+
|
303
|
+
return 0;
|
304
|
+
}
|
305
|
+
|
306
|
+
static bool
|
307
|
+
prep_trampoline(void* ctx, void* code, Closure* closure, char* errmsg, size_t errmsgsize)
|
308
|
+
{
|
309
|
+
caddr_t ptr = (caddr_t) code;
|
310
|
+
|
311
|
+
memcpy(ptr, &ffi_trampoline, trampoline_size());
|
312
|
+
// Patch the context and function addresses into the stub code
|
313
|
+
*(intptr_t *)(ptr + trampoline_ctx_offset) = (intptr_t) closure;
|
314
|
+
*(intptr_t *)(ptr + trampoline_func_offset) = (intptr_t) custom_trampoline;
|
315
|
+
|
316
|
+
return true;
|
317
|
+
}
|
318
|
+
|
319
|
+
static int
|
320
|
+
trampoline_size(void)
|
321
|
+
{
|
322
|
+
return (caddr_t) &ffi_trampoline_end - (caddr_t) &ffi_trampoline;
|
323
|
+
}
|
324
|
+
|
325
|
+
#endif /* CUSTOM_TRAMPOLINE */
|
326
|
+
|
327
|
+
|
328
|
+
void
|
329
|
+
rbffi_MethodHandle_Init(VALUE module)
|
330
|
+
{
|
331
|
+
defaultClosurePool = rbffi_ClosurePool_New(trampoline_size(), prep_trampoline, NULL);
|
332
|
+
|
333
|
+
#if defined(CUSTOM_TRAMPOLINE)
|
334
|
+
if (trampoline_offsets(&trampoline_ctx_offset, &trampoline_func_offset) != 0) {
|
335
|
+
rb_raise(rb_eFatal, "Could not locate offsets in trampoline code");
|
336
|
+
}
|
337
|
+
#else
|
338
|
+
ffi_status ffiStatus = ffi_prep_cif(&mh_cif, FFI_DEFAULT_ABI, 3, &ffi_type_ulong,
|
339
|
+
methodHandleParamTypes);
|
340
|
+
if (ffiStatus != FFI_OK) {
|
341
|
+
rb_raise(rb_eFatal, "ffi_prep_cif failed. status=%#x", ffiStatus);
|
342
|
+
}
|
343
|
+
|
344
|
+
#endif
|
345
|
+
}
|
346
|
+
|
@@ -0,0 +1,53 @@
|
|
1
|
+
/*
|
2
|
+
* Copyright (c) 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
|
+
|
28
|
+
#ifndef _METHODHANDLE_H
|
29
|
+
#define _METHODHANDLE_H
|
30
|
+
|
31
|
+
#ifdef __cplusplus
|
32
|
+
extern "C" {
|
33
|
+
#endif
|
34
|
+
|
35
|
+
#include <ruby.h>
|
36
|
+
#include "Function.h"
|
37
|
+
|
38
|
+
|
39
|
+
typedef struct MethodHandlePool MethodHandlePool;
|
40
|
+
typedef struct MethodHandle MethodHandle;
|
41
|
+
|
42
|
+
|
43
|
+
MethodHandle* rbffi_MethodHandle_Alloc(FunctionType* fnInfo, void* function);
|
44
|
+
void rbffi_MethodHandle_Free(MethodHandle* handle);
|
45
|
+
void* rbffi_MethodHandle_CodeAddress(MethodHandle* handle);
|
46
|
+
void rbffi_MethodHandle_Init(VALUE module);
|
47
|
+
|
48
|
+
#ifdef __cplusplus
|
49
|
+
}
|
50
|
+
#endif
|
51
|
+
|
52
|
+
#endif /* _METHODHANDLE_H */
|
53
|
+
|
data/ext/ffi_c/Pointer.c
CHANGED
@@ -1,3 +1,31 @@
|
|
1
|
+
/*
|
2
|
+
* Copyright (c) 2008, 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
|
+
|
1
29
|
#include <stdbool.h>
|
2
30
|
#include <stdint.h>
|
3
31
|
#include <limits.h>
|
@@ -13,7 +41,9 @@ typedef struct Pointer {
|
|
13
41
|
|
14
42
|
#define POINTER(obj) rbffi_AbstractMemory_Cast((obj), rbffi_PointerClass)
|
15
43
|
|
16
|
-
VALUE rbffi_PointerClass;
|
44
|
+
VALUE rbffi_PointerClass = Qnil;
|
45
|
+
VALUE rbffi_NullPointerSingleton = Qnil;
|
46
|
+
|
17
47
|
static void ptr_mark(Pointer* ptr);
|
18
48
|
|
19
49
|
VALUE
|
@@ -30,6 +60,8 @@ rbffi_Pointer_NewInstance(void* addr)
|
|
30
60
|
p->memory.address = addr;
|
31
61
|
p->memory.size = LONG_MAX;
|
32
62
|
p->memory.ops = &rbffi_AbstractMemoryOps;
|
63
|
+
p->memory.access = (addr == NULL) ? 0 : (MEM_RD | MEM_WR);
|
64
|
+
p->memory.typeSize = 1;
|
33
65
|
p->parent = Qnil;
|
34
66
|
|
35
67
|
return obj;
|
@@ -41,9 +73,10 @@ ptr_allocate(VALUE klass)
|
|
41
73
|
Pointer* p;
|
42
74
|
VALUE obj;
|
43
75
|
|
44
|
-
obj = Data_Make_Struct(
|
76
|
+
obj = Data_Make_Struct(klass, Pointer, NULL, -1, p);
|
45
77
|
p->parent = Qnil;
|
46
78
|
p->memory.ops = &rbffi_AbstractMemoryOps;
|
79
|
+
p->memory.access = MEM_RD | MEM_WR;
|
47
80
|
|
48
81
|
return obj;
|
49
82
|
}
|
@@ -52,28 +85,48 @@ static VALUE
|
|
52
85
|
ptr_initialize(int argc, VALUE* argv, VALUE self)
|
53
86
|
{
|
54
87
|
Pointer* p;
|
55
|
-
VALUE
|
88
|
+
VALUE rbType = Qnil, rbAddress = Qnil;
|
89
|
+
int typeSize = 1;
|
56
90
|
|
57
91
|
Data_Get_Struct(self, Pointer, p);
|
58
92
|
|
59
|
-
switch (rb_scan_args(argc, argv, "11", &
|
93
|
+
switch (rb_scan_args(argc, argv, "11", &rbType, &rbAddress)) {
|
60
94
|
case 1:
|
61
|
-
|
62
|
-
|
95
|
+
rbAddress = rbType;
|
96
|
+
typeSize = 1;
|
63
97
|
break;
|
64
98
|
case 2:
|
65
|
-
|
66
|
-
// FIXME set type_size to rbffi_type_size(type)
|
99
|
+
typeSize = rbffi_type_size(rbType);
|
67
100
|
break;
|
68
101
|
default:
|
69
102
|
rb_raise(rb_eArgError, "Invalid arguments");
|
70
103
|
}
|
71
|
-
|
72
|
-
|
104
|
+
|
105
|
+
switch (TYPE(rbAddress)) {
|
106
|
+
case T_FIXNUM:
|
107
|
+
case T_BIGNUM:
|
108
|
+
p->memory.address = (void*) (uintptr_t) NUM2LL(rbAddress);
|
109
|
+
p->memory.size = LONG_MAX;
|
110
|
+
if (p->memory.address == NULL) {
|
111
|
+
p->memory.access = 0;
|
112
|
+
}
|
113
|
+
break;
|
114
|
+
|
115
|
+
default:
|
116
|
+
if (rb_obj_is_kind_of(rbAddress, rbffi_PointerClass)) {
|
117
|
+
Pointer* orig;
|
118
|
+
|
119
|
+
p->parent = rbAddress;
|
120
|
+
Data_Get_Struct(rbAddress, Pointer, orig);
|
121
|
+
p->memory = orig->memory;
|
122
|
+
} else {
|
123
|
+
rb_raise(rb_eTypeError, "wrong argument type, expected Integer or FFI::Pointer");
|
124
|
+
}
|
125
|
+
break;
|
73
126
|
}
|
74
127
|
|
75
|
-
p->memory.
|
76
|
-
|
128
|
+
p->memory.typeSize = typeSize;
|
129
|
+
|
77
130
|
return self;
|
78
131
|
}
|
79
132
|
|
@@ -94,6 +147,8 @@ ptr_plus(VALUE self, VALUE offset)
|
|
94
147
|
p->memory.address = ptr->address + off;
|
95
148
|
p->memory.size = ptr->size == LONG_MAX ? LONG_MAX : ptr->size - off;
|
96
149
|
p->memory.ops = &rbffi_AbstractMemoryOps;
|
150
|
+
p->memory.access = ptr->access;
|
151
|
+
p->memory.typeSize = ptr->typeSize;
|
97
152
|
p->parent = self;
|
98
153
|
|
99
154
|
return retval;
|
@@ -106,7 +161,7 @@ ptr_inspect(VALUE self)
|
|
106
161
|
char tmp[100];
|
107
162
|
|
108
163
|
Data_Get_Struct(self, Pointer, ptr);
|
109
|
-
snprintf(tmp, sizeof(tmp), "#<
|
164
|
+
snprintf(tmp, sizeof(tmp), "#<FFI::Pointer address=%p>", ptr->memory.address);
|
110
165
|
|
111
166
|
return rb_str_new2(tmp);
|
112
167
|
}
|
@@ -150,6 +205,8 @@ ptr_mark(Pointer* ptr)
|
|
150
205
|
void
|
151
206
|
rbffi_Pointer_Init(VALUE moduleFFI)
|
152
207
|
{
|
208
|
+
VALUE rbNullAddress = ULL2NUM(0);
|
209
|
+
|
153
210
|
rbffi_PointerClass = rb_define_class_under(moduleFFI, "Pointer", rbffi_AbstractMemoryClass);
|
154
211
|
rb_global_variable(&rbffi_PointerClass);
|
155
212
|
|
@@ -161,4 +218,7 @@ rbffi_Pointer_Init(VALUE moduleFFI)
|
|
161
218
|
rb_define_method(rbffi_PointerClass, "address", ptr_address, 0);
|
162
219
|
rb_define_alias(rbffi_PointerClass, "to_i", "address");
|
163
220
|
rb_define_method(rbffi_PointerClass, "==", ptr_equals, 1);
|
221
|
+
|
222
|
+
rbffi_NullPointerSingleton = rb_class_new_instance(1, &rbNullAddress, rbffi_PointerClass);
|
223
|
+
rb_define_const(rbffi_PointerClass, "NULL", rbffi_NullPointerSingleton);
|
164
224
|
}
|