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,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 **) &parameters[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(rbffi_PointerClass, Pointer, NULL, -1, p);
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 type, address;
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", &type, &address)) {
93
+ switch (rb_scan_args(argc, argv, "11", &rbType, &rbAddress)) {
60
94
  case 1:
61
- p->memory.address = (void*)(uintptr_t) NUM2LL(type);
62
- // FIXME set type_size to 1
95
+ rbAddress = rbType;
96
+ typeSize = 1;
63
97
  break;
64
98
  case 2:
65
- p->memory.address = (void*)(uintptr_t) NUM2LL(address);
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
- if (p->memory.address == NULL) {
72
- p->memory.ops = &rbffi_NullPointerOps;
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.size = LONG_MAX;
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), "#<Native Pointer address=%p>", ptr->memory.address);
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
  }