Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Newer
Older
100644 920 lines (846 sloc) 26.492 kB
c3197d1 A few more docs
Evan Phoenix authored
1 /* A simple C++ wrapper around libffi. */
2
fceff3d NativeFunction, Selector, SendSite
Evan Phoenix authored
3 #include <stdio.h>
4 #include <stdlib.h>
5 #include <stdint.h>
6 #include <unistd.h>
7 #include <sys/stat.h>
8 #include <dlfcn.h>
9
10 #include "prelude.hpp"
11 #include "object.hpp"
12 #include "objects.hpp"
13 #include "vm.hpp"
14 #include "objectmemory.hpp"
15
6ac48bd Fixed a LOT of dependencies by stripping objects.hpp and prelude.hpp …
Ryan Davis authored
16 #include "builtin/array.hpp"
17 #include "builtin/class.hpp"
18 #include "builtin/fixnum.hpp"
19 #include "builtin/memorypointer.hpp"
20 #include "builtin/nativefunction.hpp"
21 #include "builtin/string.hpp"
22 #include "builtin/symbol.hpp"
23
fceff3d NativeFunction, Selector, SendSite
Evan Phoenix authored
24 #include "ffi.hpp"
9eb4748 Flesh out Task considerable more
Evan Phoenix authored
25 #include "message.hpp"
fceff3d NativeFunction, Selector, SendSite
Evan Phoenix authored
26
3197850 Fix using strlcpy and strlcat, respect CC
Evan Phoenix authored
27 extern "C" {
28 #include "strlcpy.h"
29 #include "strlcat.h"
30 }
44543a9 A number of g++ 4.2 fixes and valgrind finds
Evan Phoenix authored
31
fceff3d NativeFunction, Selector, SendSite
Evan Phoenix authored
32 #ifdef _WIN32
33 #define LIBSUFFIX ".dll"
34 #else
35 #ifdef __APPLE_CC__
36 #define LIBSUFFIX ".bundle"
37 #define LIBSUFFIX2 ".dylib"
38 #else
39 #define LIBSUFFIX ".so"
40 #endif
41 #endif
42
43 #include "ltdl.h"
44
45 #ifdef CONFIG_USE_LTDL
46 #define dlhandle lt_dlhandle
47 #define xdlopen(name) lt_dlopen(name)
48 #define xdlsym lt_dlsym
49 #define xdlsym2(name) lt_dlsym(NULL, name)
50 #define xdlerror lt_dlerror
51 #else
52 #define dlhandle void*
53 #define xdlopen(name) dlopen(name, RTLD_NOW | RTLD_GLOBAL)
54 #define xdlsym dlsym
55 #define xdlsym2(name) dlsym(RTLD_DEFAULT, name)
56 #define xdlerror dlerror
57 #endif
58
59 namespace rubinius {
60
61 void VM::init_ffi() {
72b1f02 GC root work in progress
Evan Phoenix authored
62 Class* ptr = new_class("MemoryPointer", globals.bytearray.get(), 0);
63 ptr->set_object_type(MemPtrType);
64 globals.ffi_ptr.set(ptr);
fceff3d NativeFunction, Selector, SendSite
Evan Phoenix authored
65
72b1f02 GC root work in progress
Evan Phoenix authored
66 globals.ffi_func.set(new_class("NativeFunction", globals.executable.get(),
67 NativeFunction::fields));
fceff3d NativeFunction, Selector, SendSite
Evan Phoenix authored
68
69 Module* mod = new_module("FFI");
70 mod->set_const(this, "TYPE_OBJECT", Object::i2n(this, RBX_FFI_TYPE_OBJECT));
71 mod->set_const(this, "TYPE_CHAR", Object::i2n(this, RBX_FFI_TYPE_CHAR));
72 mod->set_const(this, "TYPE_UCHAR", Object::i2n(this, RBX_FFI_TYPE_UCHAR));
73 mod->set_const(this, "TYPE_SHORT", Object::i2n(this, RBX_FFI_TYPE_SHORT));
74 mod->set_const(this, "TYPE_USHORT", Object::i2n(this, RBX_FFI_TYPE_USHORT));
75 mod->set_const(this, "TYPE_INT", Object::i2n(this, RBX_FFI_TYPE_INT));
76 mod->set_const(this, "TYPE_UINT", Object::i2n(this, RBX_FFI_TYPE_UINT));
77 mod->set_const(this, "TYPE_LONG", Object::i2n(this, RBX_FFI_TYPE_LONG));
78 mod->set_const(this, "TYPE_ULONG", Object::i2n(this, RBX_FFI_TYPE_ULONG));
79 mod->set_const(this, "TYPE_LL", Object::i2n(this, RBX_FFI_TYPE_LL));
80 mod->set_const(this, "TYPE_ULL", Object::i2n(this, RBX_FFI_TYPE_ULL));
81 mod->set_const(this, "TYPE_FLOAT", Object::i2n(this, RBX_FFI_TYPE_FLOAT));
82 mod->set_const(this, "TYPE_DOUBLE", Object::i2n(this, RBX_FFI_TYPE_DOUBLE));
83 mod->set_const(this, "TYPE_PTR", Object::i2n(this, RBX_FFI_TYPE_PTR));
84 mod->set_const(this, "TYPE_VOID", Object::i2n(this, RBX_FFI_TYPE_VOID));
85 mod->set_const(this, "TYPE_STRING", Object::i2n(this, RBX_FFI_TYPE_STRING));
86 mod->set_const(this, "TYPE_STATE", Object::i2n(this, RBX_FFI_TYPE_STATE));
87 mod->set_const(this, "TYPE_STRPTR", Object::i2n(this, RBX_FFI_TYPE_STRPTR));
88 mod->set_const(this, "TYPE_CHARARR", Object::i2n(this, RBX_FFI_TYPE_CHARARR));
89 }
90
91 MemoryPointer* MemoryPointer::create(STATE, void* ptr) {
92 MemoryPointer* obj = (MemoryPointer*)state->new_struct(G(ffi_ptr), sizeof(MemoryPointer));
93 obj->pointer = ptr;
94 return obj;
95 }
72b1f02 GC root work in progress
Evan Phoenix authored
96
fceff3d NativeFunction, Selector, SendSite
Evan Phoenix authored
97 OBJECT MemoryPointer::get_field(STATE, int offset, int type) {
98 OBJECT ret;
99 char* ptr = (char*)pointer;
100
101 ptr += offset;
102
103 #define READ(type) (*((type*)(ptr)))
104
105 switch(type) {
106 case RBX_FFI_TYPE_CHAR:
107 ret = Object::i2n(state, READ(char));
108 break;
109 case RBX_FFI_TYPE_UCHAR:
110 ret = Object::i2n(state, READ(unsigned char));
111 break;
112 case RBX_FFI_TYPE_SHORT:
113 ret = Object::i2n(state, READ(short));
114 break;
115 case RBX_FFI_TYPE_USHORT:
116 ret = Object::i2n(state, READ(unsigned short));
117 break;
118 case RBX_FFI_TYPE_INT:
119 ret = Object::i2n(state, READ(int));
120 break;
121 case RBX_FFI_TYPE_UINT:
122 ret = Object::i2n(state, READ(unsigned int));
123 break;
124 case RBX_FFI_TYPE_LONG:
125 ret = Object::i2n(state, READ(long));
126 break;
127 case RBX_FFI_TYPE_ULONG:
128 ret = Object::i2n(state, READ(unsigned long));
129 break;
130 case RBX_FFI_TYPE_FLOAT:
131 ret = Float::create(state, (double)READ(float));
132 break;
133 case RBX_FFI_TYPE_DOUBLE:
134 ret = Float::create(state, READ(double));
135 break;
136 case RBX_FFI_TYPE_LL:
137 ret = Object::ll2n(state, READ(long long));
138 break;
139 case RBX_FFI_TYPE_ULL:
140 ret = Object::ull2n(state, READ(unsigned long long));
141 break;
142 case RBX_FFI_TYPE_OBJECT:
143 ret = READ(OBJECT);
144 break;
145 case RBX_FFI_TYPE_PTR: {
146 void *lptr = READ(void*);
147 if(!lptr) {
148 ret = Qnil;
149 } else {
150 ret = MemoryPointer::create(state, lptr);
151 }
152 break;
153 }
154 case RBX_FFI_TYPE_STRING: {
155 char* result = READ(char*);
156 if(result == NULL) {
157 ret = Qnil;
158 } else {
159 ret = String::create(state, result);
160 }
161 break;
162 }
163 case RBX_FFI_TYPE_STRPTR: {
164 char* result;
165 OBJECT s, p;
166
167 result = READ(char*);
168
169 if(result == NULL) {
170 s = p = Qnil;
171 } else {
172 p = MemoryPointer::create(state, result);
173 s = String::create(state, result);
174 }
175
176 Array* ary = Array::create(state, 2);
177 ary->set(state, 0, s);
178 ary->set(state, 1, p);
179 ret = ary;
180 break;
181 }
182 default:
183 case RBX_FFI_TYPE_VOID:
184 ret = Qnil;
185 break;
186 }
187
188 return ret;
189 }
190
191 void MemoryPointer::set_field(STATE, int offset, int type, OBJECT val) {
192 char* ptr = (char*)pointer;
193
194 ptr += offset;
195
196 #define WRITE(type, val) *((type*)ptr) = (type)val
197
198 switch(type) {
199 case RBX_FFI_TYPE_CHAR:
200 type_assert(val, FixnumType, "converting to char");
52c078b Fleshing out Instruction tests, more type safety
Evan Phoenix authored
201 WRITE(char, as<Integer>(val)->n2i());
fceff3d NativeFunction, Selector, SendSite
Evan Phoenix authored
202 break;
203 case RBX_FFI_TYPE_UCHAR:
204 type_assert(val, FixnumType, "converting to unsigned char");
52c078b Fleshing out Instruction tests, more type safety
Evan Phoenix authored
205 WRITE(unsigned char, as<Integer>(val)->n2i());
fceff3d NativeFunction, Selector, SendSite
Evan Phoenix authored
206 break;
207 case RBX_FFI_TYPE_SHORT:
208 type_assert(val, FixnumType, "converting to short");
52c078b Fleshing out Instruction tests, more type safety
Evan Phoenix authored
209 WRITE(short, as<Integer>(val)->n2i());
fceff3d NativeFunction, Selector, SendSite
Evan Phoenix authored
210 break;
211 case RBX_FFI_TYPE_USHORT:
212 type_assert(val, FixnumType, "converting to unsigned short");
52c078b Fleshing out Instruction tests, more type safety
Evan Phoenix authored
213 WRITE(unsigned short, as<Integer>(val)->n2i());
fceff3d NativeFunction, Selector, SendSite
Evan Phoenix authored
214 break;
215 case RBX_FFI_TYPE_INT:
216 if(FIXNUM_P(val)) {
52c078b Fleshing out Instruction tests, more type safety
Evan Phoenix authored
217 WRITE(int, as<Integer>(val)->n2i());
fceff3d NativeFunction, Selector, SendSite
Evan Phoenix authored
218 } else {
219 Bignum *big = as<Bignum>(val);
220 type_assert(val, BignumType, "converting to int");
221 WRITE(int, big->to_i(state));
222 }
223 break;
224 case RBX_FFI_TYPE_UINT:
225 if(FIXNUM_P(val)) {
52c078b Fleshing out Instruction tests, more type safety
Evan Phoenix authored
226 WRITE(unsigned int, as<Integer>(val)->n2i());
fceff3d NativeFunction, Selector, SendSite
Evan Phoenix authored
227 } else {
228 Bignum *big = as<Bignum>(val);
229 type_assert(val, BignumType, "converting to unsigned int");
230 WRITE(unsigned int, big->to_i(state));
231 }
232 break;
233 case RBX_FFI_TYPE_LONG:
234 if(FIXNUM_P(val)) {
52c078b Fleshing out Instruction tests, more type safety
Evan Phoenix authored
235 WRITE(long, as<Integer>(val)->n2i());
fceff3d NativeFunction, Selector, SendSite
Evan Phoenix authored
236 } else {
237 Bignum *big = as<Bignum>(val);
238 type_assert(val, BignumType, "converting to long");
239 if(sizeof(long) == sizeof(long long)) {
240 WRITE(long, big->to_ll(state));
241 } else {
242 WRITE(long, big->to_i(state));
243 }
244 }
245 break;
246 case RBX_FFI_TYPE_ULONG:
247 if(FIXNUM_P(val)) {
52c078b Fleshing out Instruction tests, more type safety
Evan Phoenix authored
248 WRITE(unsigned long, as<Integer>(val)->n2i());
fceff3d NativeFunction, Selector, SendSite
Evan Phoenix authored
249 } else {
250 Bignum *big = as<Bignum>(val);
251 type_assert(val, BignumType, "converting to long");
252 if(sizeof(long) == sizeof(long long)) {
253 WRITE(unsigned long, big->to_ll(state));
254 } else {
255 WRITE(unsigned long, big->to_i(state));
256 }
257 }
258 break;
259 case RBX_FFI_TYPE_FLOAT: {
260 Float* flt = as<Float>(val);
261 type_assert(val, FloatType, "converting to float");
262 WRITE(float, flt->to_double(state));
263 break;
264 }
265 case RBX_FFI_TYPE_DOUBLE: {
266 Float* flt = as<Float>(val);
267 type_assert(val, FloatType, "converting to double");
268 WRITE(double, flt->to_double(state));
269 break;
270 }
271 case RBX_FFI_TYPE_LL:
272 if(FIXNUM_P(val)) {
52c078b Fleshing out Instruction tests, more type safety
Evan Phoenix authored
273 WRITE(long long, as<Integer>(val)->n2i());
fceff3d NativeFunction, Selector, SendSite
Evan Phoenix authored
274 } else {
275 Bignum *big = as<Bignum>(val);
276 type_assert(val, BignumType, "converting to long long");
277 WRITE(long long, big->to_ll(state));
278 }
279 break;
280 case RBX_FFI_TYPE_ULL:
281 if(FIXNUM_P(val)) {
52c078b Fleshing out Instruction tests, more type safety
Evan Phoenix authored
282 WRITE(unsigned long long, as<Integer>(val)->n2i());
fceff3d NativeFunction, Selector, SendSite
Evan Phoenix authored
283 } else {
284 Bignum *big = as<Bignum>(val);
285 type_assert(val, BignumType, "converting to unsigned long long");
286 WRITE(unsigned long long, big->to_ll(state));
287 }
288 break;
289 case RBX_FFI_TYPE_OBJECT:
290 WRITE(OBJECT, val);
291 break;
292 case RBX_FFI_TYPE_PTR:
293 if(NIL_P(val)) {
294 WRITE(void*, NULL);
295 } else {
296 MemoryPointer *mp = as<MemoryPointer>(val);
297 type_assert(val, MemPtrType, "converting to pointer");
298 WRITE(void*, mp->pointer);
299 }
300 break;
301 case RBX_FFI_TYPE_STRING: {
302 char* result;
303 if(NIL_P(val)) {
304 result = NULL;
305 } else {
306 String* str = as<String>(val);
307 /* TODO this is probably not correct. Saving away an
308 * internal pointer to the string means that when the string
309 * moves, the data will point at the wrong place. Probably need to
310 * copy the string data instead */
311 result = str->byte_address(state);
312 }
313 WRITE(char*, result);
314 break;
315 }
316 default:
317 sassert(0);
318 }
319 }
320
321 size_t NativeFunction::type_size(size_t type) {
322 switch(type) {
323 case RBX_FFI_TYPE_CHAR:
324 case RBX_FFI_TYPE_UCHAR:
325 return sizeof(char);
326
327 case RBX_FFI_TYPE_SHORT:
328 case RBX_FFI_TYPE_USHORT:
329 return sizeof(short);
330
331 case RBX_FFI_TYPE_INT:
332 case RBX_FFI_TYPE_UINT:
333 return sizeof(int);
334
335 case RBX_FFI_TYPE_LONG:
336 case RBX_FFI_TYPE_ULONG:
337 return sizeof(long);
338
339 case RBX_FFI_TYPE_LL:
340 case RBX_FFI_TYPE_ULL:
341 return sizeof(long long);
342
343 case RBX_FFI_TYPE_FLOAT:
344 return sizeof(float);
345
346 case RBX_FFI_TYPE_DOUBLE:
347 return sizeof(double);
348
349 case RBX_FFI_TYPE_PTR:
350 case RBX_FFI_TYPE_STRING:
351 case RBX_FFI_TYPE_STATE:
352 case RBX_FFI_TYPE_STRPTR:
353 case RBX_FFI_TYPE_OBJECT:
354 return sizeof(void*);
355
356 default:
357 return -1;
358 }
359 }
360
361 void* NativeFunction::find_symbol(STATE, OBJECT opath, String* name) {
362 dlhandle lib;
363 void *ep;
364 char sys_name[128];
365
366 if(opath->nil_p()) {
367 lib = xdlopen(NULL);
368 if(!lib) return NULL;
369 } else {
370 String* path = as<String>(opath);
371
372 /* path is a string like 'ext/gzip', we turn that into 'ext/gzip.so'
373 or whatever the library suffix is. */
44543a9 A number of g++ 4.2 fixes and valgrind finds
Evan Phoenix authored
374 memset(sys_name, 0, 128);
fceff3d NativeFunction, Selector, SendSite
Evan Phoenix authored
375 strlcpy(sys_name, *path, sizeof(sys_name));
376 strlcat(sys_name, LIBSUFFIX, sizeof(sys_name));
377
378 /* Open it up. If this fails, then we just pretend like
379 the library isn't there. */
380 lib = xdlopen(sys_name);
381 if(!lib) {
382 #ifdef LIBSUFFIX2
383 memset(sys_name, 0, 128);
384 strlcpy(sys_name, *path, sizeof(sys_name));
385 strlcat(sys_name, LIBSUFFIX2, sizeof(sys_name));
386
387 lib = xdlopen(sys_name);
388 if(!lib) return NULL;
389 #else
390 return NULL;
391 #endif
392 }
393 }
394
395 ep = xdlsym(lib, *name);
396 if(!ep) {
397 ep = xdlsym2(*name);
398 }
399 return ep;
400 }
401
402 NativeFunction* NativeFunction::create(STATE, OBJECT name, int args) {
403 NativeFunction* nf = (NativeFunction*)state->new_object(G(ffi_func));
404 SET(nf, primitive, state->symbol("nfunc_call"));
405 SET(nf, required, Object::i2n(state, args));
406 SET(nf, serial, Object::i2n(0));
407 SET(nf, name, name);
408 SET(nf, file, state->symbol("<system>"));
409 SET(nf, data, Qnil);
410 return nf;
411 }
412
413 void NativeFunction::bind(STATE, int arg_count, int *arg_types,
414 int ret_type, void *func) {
415
416 ffi_type **types;
417 ffi_status status;
418 ffi_type *rtype;
419 struct ffi_stub *stub;
420 int i;
421
422 types = ALLOC_N(ffi_type*, arg_count);
423
424 for(i = 0; i < arg_count; i++) {
425 switch(arg_types[i]) {
426 case RBX_FFI_TYPE_CHAR:
427 types[i] = &ffi_type_schar;
428 break;
429 case RBX_FFI_TYPE_UCHAR:
430 types[i] = &ffi_type_uchar;
431 break;
432 case RBX_FFI_TYPE_SHORT:
433 types[i] = &ffi_type_sshort;
434 break;
435 case RBX_FFI_TYPE_USHORT:
436 types[i] = &ffi_type_ushort;
437 break;
438 case RBX_FFI_TYPE_INT:
439 types[i] = &ffi_type_sint;
440 break;
441 case RBX_FFI_TYPE_UINT:
442 types[i] = &ffi_type_uint;
443 break;
444 case RBX_FFI_TYPE_LONG:
445 types[i] = &ffi_type_slong;
446 break;
447 case RBX_FFI_TYPE_ULONG:
448 types[i] = &ffi_type_ulong;
449 break;
450 case RBX_FFI_TYPE_FLOAT:
451 types[i] = &ffi_type_float;
452 break;
453 case RBX_FFI_TYPE_DOUBLE:
454 types[i] = &ffi_type_double;
455 break;
456 case RBX_FFI_TYPE_LL:
457 types[i] = &ffi_type_sint64;
458 break;
459 case RBX_FFI_TYPE_ULL:
460 types[i] = &ffi_type_uint64;
461 break;
462 case RBX_FFI_TYPE_OBJECT:
463 case RBX_FFI_TYPE_PTR:
464 case RBX_FFI_TYPE_STRING:
465 case RBX_FFI_TYPE_STATE:
466 types[i] = &ffi_type_pointer;
467 break;
468 }
469 }
470
471 switch(ret_type) {
472 case RBX_FFI_TYPE_CHAR:
473 rtype = &ffi_type_schar;
474 break;
475 case RBX_FFI_TYPE_UCHAR:
476 rtype = &ffi_type_uchar;
477 break;
478 case RBX_FFI_TYPE_SHORT:
479 rtype = &ffi_type_sshort;
480 break;
481 case RBX_FFI_TYPE_USHORT:
482 rtype = &ffi_type_ushort;
483 break;
484 case RBX_FFI_TYPE_INT:
485 rtype = &ffi_type_sint;
486 break;
487 case RBX_FFI_TYPE_UINT:
488 rtype = &ffi_type_uint;
489 break;
490 case RBX_FFI_TYPE_LONG:
491 rtype = &ffi_type_slong;
492 break;
493 case RBX_FFI_TYPE_ULONG:
494 rtype = &ffi_type_ulong;
495 break;
496 case RBX_FFI_TYPE_FLOAT:
497 rtype = &ffi_type_float;
498 break;
499 case RBX_FFI_TYPE_DOUBLE:
500 rtype = &ffi_type_double;
501 break;
502 case RBX_FFI_TYPE_LL:
503 rtype = &ffi_type_sint64;
504 break;
505 case RBX_FFI_TYPE_ULL:
506 rtype = &ffi_type_uint64;
507 break;
508 case RBX_FFI_TYPE_OBJECT:
509 case RBX_FFI_TYPE_PTR:
510 case RBX_FFI_TYPE_STRING:
511 case RBX_FFI_TYPE_STATE:
512 case RBX_FFI_TYPE_STRPTR:
513 rtype = &ffi_type_pointer;
514 break;
515 default:
516 case RBX_FFI_TYPE_VOID:
517 rtype = &ffi_type_void;
518 break;
519 }
520
521 stub = ALLOC_N(struct ffi_stub, 1);
522 stub->ret_type = ret_type;
523 stub->ep = func;
524 stub->arg_count = arg_count;
525 stub->arg_types = ALLOC_N(int, arg_count);
526 memcpy(stub->arg_types, arg_types, sizeof(int) * arg_count);
527 status = ffi_prep_cif(&stub->cif, FFI_DEFAULT_ABI, arg_count, rtype, types);
528
529 if(status != FFI_OK) {
530 XFREE(stub);
531 sassert(status == FFI_OK);
532 }
533
534 data = MemoryPointer::create(state, (void*)stub);
535 }
536
537 /* The main interface function, handles looking up the pointer in the library,
538 * generating the stub, wrapping it up and attaching it to the module.
539 */
540 NativeFunction* NativeFunction::bind(STATE, String* library, String* name,
541 Array* args, OBJECT ret) {
542 void *ep;
543 int *arg_types;
544 int ret_type;
545 int i, tot, arg_count;
546 OBJECT type; /* meths; */
547
548 ep = NativeFunction::find_symbol(state, library, name);
549 if(!ep) return (NativeFunction*)Qnil;
550
551 tot = args->size();
552 arg_count = tot;
553 if(tot > 0) {
554 arg_types = ALLOC_N(int, tot);
555
556 for(i = 0; i < tot; i++) {
557 type = args->get(state, i);
558 if(!type->fixnum_p()) return (NativeFunction*)Qnil;
52c078b Fleshing out Instruction tests, more type safety
Evan Phoenix authored
559 arg_types[i] = as<Integer>(type)->n2i();
fceff3d NativeFunction, Selector, SendSite
Evan Phoenix authored
560
561 /* State can only be passed as the first arg, and it's invisible,
562 ie doesn't get seen as in onbound arg by ruby. But it can ONLY
563 be the first arg. */
564 if(arg_types[i] == RBX_FFI_TYPE_STATE) {
565 if(i == 0) {
566 arg_count--;
567 } else {
568 XFREE(arg_types);
569 printf("Invalid arg types.\n");
570 return (NativeFunction*)Qnil;
571 }
572 }
573 }
574 } else {
575 arg_types = NULL;
576 }
577
52c078b Fleshing out Instruction tests, more type safety
Evan Phoenix authored
578 ret_type = as<Integer>(ret)->n2i();
fceff3d NativeFunction, Selector, SendSite
Evan Phoenix authored
579
580 NativeFunction* func = NativeFunction::create(state, name->to_sym(state), arg_count);
581 func->bind(state, tot, arg_types, ret_type, ep);
ee319b9 Fix awesome memory bug in ffi's argument handling
Evan Phoenix authored
582
fceff3d NativeFunction, Selector, SendSite
Evan Phoenix authored
583 return func;
584 }
585
586 void **NativeFunction::marshal_arguments(STATE, Message* msg) {
587 void **values;
588 OBJECT obj;
589 struct ffi_stub *stub = (struct ffi_stub*)data->pointer;
590
591 values = ALLOC_N(void*, stub->arg_count);
ee319b9 Fix awesome memory bug in ffi's argument handling
Evan Phoenix authored
592
fceff3d NativeFunction, Selector, SendSite
Evan Phoenix authored
593 for(size_t i = 0; i < stub->arg_count; i++) {
594 switch(stub->arg_types[i]) {
595 case RBX_FFI_TYPE_CHAR: {
ee319b9 Fix awesome memory bug in ffi's argument handling
Evan Phoenix authored
596 char *tmp = (char*)malloc(sizeof(char));
fceff3d NativeFunction, Selector, SendSite
Evan Phoenix authored
597 obj = msg->get_argument(i);
598 type_assert(obj, FixnumType, "converting to char");
52c078b Fleshing out Instruction tests, more type safety
Evan Phoenix authored
599 *tmp = (char)as<Integer>(obj)->n2i();
fceff3d NativeFunction, Selector, SendSite
Evan Phoenix authored
600 values[i] = tmp;
601 break;
602 }
603 case RBX_FFI_TYPE_UCHAR: {
ee319b9 Fix awesome memory bug in ffi's argument handling
Evan Phoenix authored
604 unsigned char *tmp = (unsigned char*)malloc(sizeof(char));
fceff3d NativeFunction, Selector, SendSite
Evan Phoenix authored
605 obj = msg->get_argument(i);
606 type_assert(obj, FixnumType, "converting to unsigned char");
52c078b Fleshing out Instruction tests, more type safety
Evan Phoenix authored
607 *tmp = (unsigned char)as<Integer>(obj)->n2i();
fceff3d NativeFunction, Selector, SendSite
Evan Phoenix authored
608 values[i] = tmp;
609 break;
610 }
611 case RBX_FFI_TYPE_SHORT: {
ee319b9 Fix awesome memory bug in ffi's argument handling
Evan Phoenix authored
612 short *tmp = (short*)malloc(sizeof(short));
fceff3d NativeFunction, Selector, SendSite
Evan Phoenix authored
613 obj = msg->get_argument(i);
614 if(FIXNUM_P(obj)) {
52c078b Fleshing out Instruction tests, more type safety
Evan Phoenix authored
615 *tmp = (short)as<Integer>(obj)->n2i();
fceff3d NativeFunction, Selector, SendSite
Evan Phoenix authored
616 } else {
617 type_assert(obj, BignumType, "converting to short");
618 *tmp = as<Bignum>(obj)->to_i(state);
619 }
52c078b Fleshing out Instruction tests, more type safety
Evan Phoenix authored
620 *tmp = (short)as<Integer>(obj)->n2i();
fceff3d NativeFunction, Selector, SendSite
Evan Phoenix authored
621 values[i] = tmp;
622 break;
623 }
624 case RBX_FFI_TYPE_USHORT: {
ee319b9 Fix awesome memory bug in ffi's argument handling
Evan Phoenix authored
625 unsigned short *tmp = (unsigned short*)malloc(sizeof(short));
fceff3d NativeFunction, Selector, SendSite
Evan Phoenix authored
626 obj = msg->get_argument(i);
627 if(FIXNUM_P(obj)) {
52c078b Fleshing out Instruction tests, more type safety
Evan Phoenix authored
628 *tmp = (unsigned short)as<Integer>(obj)->n2i();
fceff3d NativeFunction, Selector, SendSite
Evan Phoenix authored
629 } else {
630 type_assert(obj, BignumType, "converting to unsigned short");
631 *tmp = (unsigned short)as<Bignum>(obj)->to_i(state);
632 }
52c078b Fleshing out Instruction tests, more type safety
Evan Phoenix authored
633 *tmp = (unsigned short)as<Integer>(obj)->n2i();
fceff3d NativeFunction, Selector, SendSite
Evan Phoenix authored
634 values[i] = tmp;
635 break;
636 }
637 case RBX_FFI_TYPE_INT: {
ee319b9 Fix awesome memory bug in ffi's argument handling
Evan Phoenix authored
638 int *tmp = (int*)malloc(sizeof(int));
fceff3d NativeFunction, Selector, SendSite
Evan Phoenix authored
639 obj = msg->get_argument(i);
640 if(FIXNUM_P(obj)) {
52c078b Fleshing out Instruction tests, more type safety
Evan Phoenix authored
641 *tmp = (int)as<Integer>(obj)->n2i();
fceff3d NativeFunction, Selector, SendSite
Evan Phoenix authored
642 } else {
643 type_assert(obj, BignumType, "converting to int");
644 *tmp = as<Bignum>(obj)->to_i(state);
645 }
646 values[i] = tmp;
647 break;
648 }
649 case RBX_FFI_TYPE_UINT: {
ee319b9 Fix awesome memory bug in ffi's argument handling
Evan Phoenix authored
650 unsigned int *tmp = (unsigned int*)malloc(sizeof(unsigned int));
fceff3d NativeFunction, Selector, SendSite
Evan Phoenix authored
651 obj = msg->get_argument(i);
652 if(FIXNUM_P(obj)) {
52c078b Fleshing out Instruction tests, more type safety
Evan Phoenix authored
653 *tmp = (int)as<Integer>(obj)->n2i();
fceff3d NativeFunction, Selector, SendSite
Evan Phoenix authored
654 } else {
655 type_assert(obj, BignumType, "converting to int");
656 *tmp = as<Bignum>(obj)->to_i(state);
657 }
658 values[i] = tmp;
659 break;
660 }
661 case RBX_FFI_TYPE_LONG: {
ee319b9 Fix awesome memory bug in ffi's argument handling
Evan Phoenix authored
662 long *tmp = (long*)malloc(sizeof(long));
fceff3d NativeFunction, Selector, SendSite
Evan Phoenix authored
663 obj = msg->get_argument(i);
664 if(FIXNUM_P(obj)) {
52c078b Fleshing out Instruction tests, more type safety
Evan Phoenix authored
665 *tmp = (long)as<Integer>(obj)->n2i();
fceff3d NativeFunction, Selector, SendSite
Evan Phoenix authored
666 } else {
667 type_assert(obj, BignumType, "converting to long");
668 if(sizeof(long) == sizeof(long long)) {
669 *tmp = (long)as<Bignum>(obj)->to_ll(state);
670 } else {
671 *tmp = as<Bignum>(obj)->to_i(state);
672 }
673 }
674 values[i] = tmp;
675 break;
676 }
677 case RBX_FFI_TYPE_ULONG: {
ee319b9 Fix awesome memory bug in ffi's argument handling
Evan Phoenix authored
678 unsigned long *tmp = (unsigned long*)malloc(sizeof(long));
fceff3d NativeFunction, Selector, SendSite
Evan Phoenix authored
679 obj = msg->get_argument(i);
680 if(FIXNUM_P(obj)) {
52c078b Fleshing out Instruction tests, more type safety
Evan Phoenix authored
681 *tmp = (unsigned long)as<Integer>(obj)->n2i();
fceff3d NativeFunction, Selector, SendSite
Evan Phoenix authored
682 } else {
683 type_assert(obj, BignumType, "converting to unsigned long");
684 if(sizeof(long) == sizeof(long long)) {
685 *tmp = (unsigned long)as<Bignum>(obj)->to_ll(state);
686 } else {
687 *tmp = as<Bignum>(obj)->to_i(state);
688 }
689 }
690 values[i] = tmp;
691 break;
692 }
693 case RBX_FFI_TYPE_FLOAT: {
ee319b9 Fix awesome memory bug in ffi's argument handling
Evan Phoenix authored
694 float *tmp = (float*)malloc(sizeof(float));
fceff3d NativeFunction, Selector, SendSite
Evan Phoenix authored
695 obj = msg->get_argument(i);
696 type_assert(obj, FloatType, "converting to float");
697 *tmp = (float)as<Float>(obj)->to_double(state);
698 values[i] = tmp;
699 break;
700 }
701 case RBX_FFI_TYPE_DOUBLE: {
ee319b9 Fix awesome memory bug in ffi's argument handling
Evan Phoenix authored
702 double *tmp = (double*)malloc(sizeof(double));
fceff3d NativeFunction, Selector, SendSite
Evan Phoenix authored
703 obj = msg->get_argument(i);
704 type_assert(obj, FloatType, "converting to double");
705 *tmp = as<Float>(obj)->to_double(state);
706 values[i] = tmp;
707 break;
708 }
709 case RBX_FFI_TYPE_LL: {
ee319b9 Fix awesome memory bug in ffi's argument handling
Evan Phoenix authored
710 long long *tmp = (long long*)malloc(sizeof(long long));
fceff3d NativeFunction, Selector, SendSite
Evan Phoenix authored
711 obj = msg->get_argument(i);
712 if(FIXNUM_P(obj)) {
52c078b Fleshing out Instruction tests, more type safety
Evan Phoenix authored
713 *tmp = (long long)as<Integer>(obj)->n2i();
fceff3d NativeFunction, Selector, SendSite
Evan Phoenix authored
714 } else {
715 type_assert(obj, BignumType, "converting to unsigned long");
716 *tmp = (long long)as<Bignum>(obj)->to_ll(state);
717 }
718 values[i] = tmp;
719 break;
720 }
721 case RBX_FFI_TYPE_ULL: {
ee319b9 Fix awesome memory bug in ffi's argument handling
Evan Phoenix authored
722 unsigned long long *tmp = (unsigned long long*)malloc(sizeof(long long));
fceff3d NativeFunction, Selector, SendSite
Evan Phoenix authored
723 obj = msg->get_argument(i);
724 if(FIXNUM_P(obj)) {
52c078b Fleshing out Instruction tests, more type safety
Evan Phoenix authored
725 *tmp = (unsigned long long)as<Integer>(obj)->n2i();
fceff3d NativeFunction, Selector, SendSite
Evan Phoenix authored
726 } else {
727 type_assert(obj, BignumType, "converting to unsigned long");
728 *tmp = (unsigned long long)as<Bignum>(obj)->to_ll(state);
729 }
730 values[i] = tmp;
731 break;
732 }
733 case RBX_FFI_TYPE_STATE:
734 values[i] = &state;
735 break;
736 case RBX_FFI_TYPE_OBJECT: {
ee319b9 Fix awesome memory bug in ffi's argument handling
Evan Phoenix authored
737 OBJECT *tmp = (OBJECT*)malloc(sizeof(OBJECT));
fceff3d NativeFunction, Selector, SendSite
Evan Phoenix authored
738 obj = msg->get_argument(i);
739 *tmp = obj;
740 values[i] = tmp;
741 break;
742 }
743 case RBX_FFI_TYPE_PTR: {
ee319b9 Fix awesome memory bug in ffi's argument handling
Evan Phoenix authored
744 void **tmp = (void**)malloc(sizeof(void*));
fceff3d NativeFunction, Selector, SendSite
Evan Phoenix authored
745 obj = msg->get_argument(i);
746 if(NIL_P(obj)) {
747 *tmp = NULL;
748 } else {
749 MemoryPointer *mp = as<MemoryPointer>(obj);
750 type_assert(obj, MemPtrType, "converting to pointer");
751 *tmp = mp->pointer;
752 }
753 values[i] = tmp;
754 break;
755 }
756 case RBX_FFI_TYPE_STRING: {
ee319b9 Fix awesome memory bug in ffi's argument handling
Evan Phoenix authored
757 char **tmp = (char**)malloc(sizeof(char*));
fceff3d NativeFunction, Selector, SendSite
Evan Phoenix authored
758 obj = msg->get_argument(i);
759 if(NIL_P(obj)) {
760 *tmp = NULL;
761 } else {
762 String *so = as<String>(obj);
763 *tmp = so->byte_address(state);
764 }
765 values[i] = tmp;
766 break;
767 }
768 }
769 }
770
771 return values;
772 }
773
774 OBJECT NativeFunction::call(STATE, Message* msg) {
775 OBJECT ret;
776
777 struct ffi_stub *stub = (struct ffi_stub*)data->pointer;
778
779 void **values = marshal_arguments(state, msg);
780
781 switch(stub->ret_type) {
782 case RBX_FFI_TYPE_CHAR: {
783 ffi_arg result;
784 ffi_call(&stub->cif, FFI_FN(stub->ep), &result, values);
785 ret = Object::i2n(state, (char)result);
786 break;
787 }
788 case RBX_FFI_TYPE_UCHAR: {
789 ffi_arg result;
790 ffi_call(&stub->cif, FFI_FN(stub->ep), &result, values);
791 ret = Object::ui2n(state, (unsigned char)result);
792 break;
793 }
794 case RBX_FFI_TYPE_SHORT: {
795 ffi_arg result;
796 ffi_call(&stub->cif, FFI_FN(stub->ep), &result, values);
797 ret = Object::i2n(state, (short)result);
798 break;
799 }
800 case RBX_FFI_TYPE_USHORT: {
801 ffi_arg result;
802 ffi_call(&stub->cif, FFI_FN(stub->ep), &result, values);
803 ret = Object::ui2n(state, (unsigned short)result);
804 break;
805 }
806 case RBX_FFI_TYPE_INT: {
807 ffi_arg result;
808 ffi_call(&stub->cif, FFI_FN(stub->ep), &result, values);
809 ret = Object::i2n(state, (int)result);
810 break;
811 }
812 case RBX_FFI_TYPE_UINT: {
813 ffi_arg result;
814 ffi_call(&stub->cif, FFI_FN(stub->ep), &result, values);
815 ret = Object::ui2n(state, (unsigned int)result);
816 break;
817 }
818 case RBX_FFI_TYPE_LONG: {
819 long result;
820 ffi_call(&stub->cif, FFI_FN(stub->ep), &result, values);
821 ret = Object::i2n(state, result);
822 break;
823 }
824 case RBX_FFI_TYPE_ULONG: {
825 unsigned long result;
826 ffi_call(&stub->cif, FFI_FN(stub->ep), &result, values);
827 ret = Object::ui2n(state, result);
828 break;
829 }
830 case RBX_FFI_TYPE_FLOAT: {
831 float result;
832 ffi_call(&stub->cif, FFI_FN(stub->ep), &result, values);
833 ret = Float::create(state, (double)result);
834 break;
835 }
836 case RBX_FFI_TYPE_DOUBLE: {
837 double result;
838 ffi_call(&stub->cif, FFI_FN(stub->ep), &result, values);
839 ret = Float::create(state, result);
840 break;
841 }
842 case RBX_FFI_TYPE_LL: {
843 long long result;
844 ffi_call(&stub->cif, FFI_FN(stub->ep), &result, values);
845 ret = Object::ll2n(state, result);
846 break;
847 }
848 case RBX_FFI_TYPE_ULL: {
849 unsigned long long result;
850 ffi_call(&stub->cif, FFI_FN(stub->ep), &result, values);
851 ret = Object::ull2n(state, result);
852 break;
853 }
854 case RBX_FFI_TYPE_OBJECT: {
855 ffi_call(&stub->cif, FFI_FN(stub->ep), &ret, values);
856 break;
857 }
858 case RBX_FFI_TYPE_PTR: {
859 void *result;
860 ffi_call(&stub->cif, FFI_FN(stub->ep), &result, values);
861 if(result == NULL) {
862 ret = Qnil;
863 } else {
864 ret = MemoryPointer::create(state, result);
865 }
866 break;
867 }
868 case RBX_FFI_TYPE_STRING: {
869 char* result;
870 ffi_call(&stub->cif, FFI_FN(stub->ep), &result, values);
871 if(result == NULL) {
872 ret = Qnil;
873 } else {
874 ret = String::create(state, result);
875 }
876 break;
877 }
878 case RBX_FFI_TYPE_STRPTR: {
879 char* result;
880 OBJECT s, p;
881
882 ffi_call(&stub->cif, FFI_FN(stub->ep), &result, values);
883
884 if(result == NULL) {
885 s = p = Qnil;
886 } else {
887 p = MemoryPointer::create(state, result);
888 s = String::create(state, result);
889 }
890
891 Array* ary = Array::create(state, 2);
892 ary->set(state, 0, s);
893 ary->set(state, 1, p);
894 ret = ary;
895 break;
896 }
897 default:
898 case RBX_FFI_TYPE_VOID: {
899 ffi_arg result;
900 ffi_call(&stub->cif, FFI_FN(stub->ep), &result, values);
901 ret = Qnil;
902 break;
903 }
904 }
905
ee319b9 Fix awesome memory bug in ffi's argument handling
Evan Phoenix authored
906 /* TODO: fix marshal_argumets to not malloc memory for every arg.
907 * use a single block. */
908 /* Free the memory used to store the args */
909 for(size_t i = 0; i < stub->arg_count; i++) {
910 free(values[i]);
911 }
912
913 free(values);
914
fceff3d NativeFunction, Selector, SendSite
Evan Phoenix authored
915 return ret;
916 }
917
918
919 };
Something went wrong with that request. Please try again.