Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

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