Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

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