1/* 2 * Copyright (c) 2006-2008, The RubyCocoa Project. 3 * Copyright (c) 2001-2006, FUJIMOTO Hisakuni. 4 * All Rights Reserved. 5 * 6 * RubyCocoa is free software, covered under either the Ruby's license or the 7 * LGPL. See the COPYRIGHT file for more information. 8 */ 9 10#import <Foundation/Foundation.h> 11#import "libffi.h" 12#import "ocdata_conv.h" 13#import "BridgeSupport.h" 14#import "ocexception.h" 15#import "cls_objcid.h" 16#import "cls_objcptr.h" 17#import "internal_macros.h" 18#import <st.h> 19#include <sys/mman.h> // for mmap() 20 21#define FFI_LOG(fmt, args...) DLOG("LIBFFI", fmt, ##args) 22 23ffi_type * 24bs_boxed_ffi_type(struct bsBoxed *bs_boxed) 25{ 26 if (bs_boxed->ffi_type == NULL) { 27 if (bs_boxed->type == bsBoxedStructType) { 28 unsigned i; 29 30 bs_boxed->ffi_type = (ffi_type *)malloc(sizeof(ffi_type)); 31 ASSERT_ALLOC(bs_boxed->ffi_type); 32 33 bs_boxed->ffi_type->size = 0; // IMPORTANT: we need to leave this to 0 and not set the real size 34 bs_boxed->ffi_type->alignment = 0; 35 bs_boxed->ffi_type->type = FFI_TYPE_STRUCT; 36 bs_boxed->ffi_type->elements = malloc((bs_boxed->opt.s.field_count + 1) * sizeof(ffi_type *)); 37 ASSERT_ALLOC(bs_boxed->ffi_type->elements); 38 for (i = 0; i < bs_boxed->opt.s.field_count; i++) { 39 char *octypestr; 40 41 octypestr = bs_boxed->opt.s.fields[i].encoding; 42 bs_boxed->ffi_type->elements[i] = ffi_type_for_octype(octypestr); 43 } 44 bs_boxed->ffi_type->elements[bs_boxed->opt.s.field_count] = NULL; 45 } 46 else if (bs_boxed->type == bsBoxedOpaqueType) { 47 // FIXME we assume that boxed types are pointers, but maybe we should analyze the encoding. 48 bs_boxed->ffi_type = &ffi_type_pointer; 49 } 50 } 51 52 return bs_boxed->ffi_type; 53} 54 55static struct st_table *ary_ffi_types = NULL; 56 57static ffi_type * 58fake_ary_ffi_type (unsigned bytes, unsigned align) 59{ 60 ffi_type *type; 61 unsigned i; 62 63 assert(bytes > 0); 64 65 if (ary_ffi_types == NULL) 66 ary_ffi_types = st_init_numtable(); 67 68 if (st_lookup(ary_ffi_types, (st_data_t)bytes, (st_data_t *)&type)) 69 return type; 70 71 type = (ffi_type *)malloc(sizeof(ffi_type)); 72 ASSERT_ALLOC(type); 73 74 type->size = bytes; 75 type->alignment = align; 76 type->type = FFI_TYPE_STRUCT; 77 type->elements = malloc(bytes * sizeof(ffi_type *)); 78 ASSERT_ALLOC(type->elements); 79 for (i = 0; i < bytes; i++) 80 type->elements[i] = &ffi_type_uchar; 81 82 st_insert(ary_ffi_types, (st_data_t)bytes, (st_data_t)type); 83 84 return type; 85} 86 87ffi_type * 88ffi_type_for_octype (const char *octypestr) 89{ 90 octypestr = encoding_skip_qualifiers(octypestr); 91 92 switch (*octypestr) { 93 case _C_ID: 94 case _C_CLASS: 95 case _C_SEL: 96 case _C_CHARPTR: 97 case _C_PTR: 98 return &ffi_type_pointer; 99 100 case _C_BOOL: 101 case _C_UCHR: 102 return &ffi_type_uchar; 103 104 case _C_CHR: 105 return &ffi_type_schar; 106 107 case _C_SHT: 108 return &ffi_type_sshort; 109 110 case _C_USHT: 111 return &ffi_type_ushort; 112 113 case _C_INT: 114 return &ffi_type_sint; 115 116 case _C_UINT: 117 return &ffi_type_uint; 118 119 case _C_LNG: 120 return sizeof(int) == sizeof(long) ? &ffi_type_sint : &ffi_type_slong; 121 122#if defined(_C_LNG_LNG) 123 case _C_LNG_LNG: 124 return &ffi_type_sint64; 125#endif 126 127 case _C_ULNG: 128 return sizeof(unsigned int) == sizeof(unsigned long) ? &ffi_type_uint : &ffi_type_ulong; 129 130#if defined(_C_ULNG_LNG) 131 case _C_ULNG_LNG: 132 return &ffi_type_uint64; 133#endif 134 135 case _C_FLT: 136 return &ffi_type_float; 137 138 case _C_DBL: 139 return &ffi_type_double; 140 141 case _C_VOID: 142 return &ffi_type_void; 143 144 case _C_BFLD: 145 { 146 unsigned int size; 147 148 size = ocdata_size(octypestr); 149 if (size > 0) { 150 if (size == 1) 151 return &ffi_type_uchar; 152 else if (size == 2) 153 return &ffi_type_ushort; 154 else if (size <= 4) 155 return &ffi_type_uint; 156 else 157 return fake_ary_ffi_type(size, 0); 158 } 159 } 160 break; 161 162 case _C_ARY_B: 163 { 164#if __LP64__ 165 unsigned long size, align; 166#else 167 unsigned int size, align; 168#endif 169 170 @try { 171 NSGetSizeAndAlignment(octypestr, &size, &align); 172 } 173 @catch (id exception) { 174 rb_raise(rb_eRuntimeError, "Cannot compute size of type `%s' : %s", 175 octypestr, [[exception description] UTF8String]); 176 } 177 178 if (size > 0) 179 return fake_ary_ffi_type(size, align); 180 } 181 break; 182 183 default: 184 { 185 struct bsBoxed *bs_boxed; 186 187 bs_boxed = find_bs_boxed_by_encoding(octypestr); 188 if (bs_boxed != NULL) 189 return bs_boxed_ffi_type(bs_boxed); 190 } 191 break; 192 } 193 194 NSLog (@"XXX returning ffi type void for unrecognized encoding '%s'", octypestr); 195 196 return &ffi_type_void; 197} 198 199static inline BOOL 200__is_in(int elem, int *array, unsigned count) 201{ 202 unsigned i; 203 for (i = 0; i < count; i++) { 204 if (array[i] == elem) 205 return YES; 206 } 207 return NO; 208} 209 210VALUE 211rb_ffi_dispatch ( 212 struct bsCallEntry *call_entry, 213 char **arg_octypes, 214 int expected_argc, 215 int given_argc, 216 int argc_delta, 217 VALUE *argv, 218 ffi_type **arg_types, 219 void **arg_values, 220 char *ret_octype, 221 void *func_sym, 222 void (*retain_if_necessary)(VALUE arg, BOOL retval, void *ctx), 223 void *retain_if_necessary_ctx, 224 VALUE *result) 225{ 226 int length_args[MAX_ARGS]; 227 unsigned length_args_count; 228 int pointers_args[MAX_ARGS]; 229 unsigned pointers_args_count; 230 unsigned skipped; 231 int i; 232 ffi_type * ret_type; 233 void * retval = NULL; 234 ffi_cif cif; 235 VALUE exception; 236 237#define ARG_OCTYPESTR(i) \ 238 (arg_octypes != NULL ? arg_octypes[i] : call_entry->argv[i].octypestr) 239 240#define IS_POINTER_ARG(idx) \ 241 (__is_in(idx, pointers_args, pointers_args_count)) 242 243#define IS_LENGTH_ARG(idx) \ 244 (__is_in(idx, length_args, length_args_count)) 245 246 FFI_LOG("argc expected %d given %d delta %d", expected_argc, given_argc, 247 argc_delta); 248 249 // Check arguments count. 250 length_args_count = pointers_args_count = 0; 251 if (call_entry != NULL) { 252 for (i = 0; i < call_entry->argc; i++) { 253 struct bsArg *arg; 254 255 arg = &call_entry->argv[i]; 256 // The given argument is a C array with a length determined by the value 257 // of another argument, like: 258 // [NSArray +arrayWithObjects:length:] 259 // If 'in' or 'inout, the 'length' argument is not necessary (but the 260 // 'array' is). If 'out', the 'array' argument is not necessary (but the 261 // 'length' is). 262 if (arg->c_ary_type == bsCArrayArgDelimitedByArg) { 263 unsigned j; 264 BOOL already; 265 266 // Some methods may accept multiple 'array' 'in' arguments that refer 267 // to the same 'length' argument, like: 268 // [NSDictionary +dictionaryWithObjects:forKeys:count:] 269 for (j = 0, already = NO; j < length_args_count; j++) { 270 if (length_args[j] == arg->c_ary_type_value) { 271 already = YES; 272 break; 273 } 274 } 275 if (already) 276 continue; 277 278 length_args[length_args_count++] = arg->c_ary_type_value; 279 } 280 } 281 FFI_LOG("detected %d array length argument(s)", length_args_count); 282 } 283 284 if (expected_argc - length_args_count != given_argc) { 285 for (i = 0; i < expected_argc; i++) { 286 char *type = ARG_OCTYPESTR(i); 287 type = (char *)encoding_skip_qualifiers(type); 288 if (given_argc + pointers_args_count < expected_argc 289 && (i >= given_argc || !NIL_P(argv[i])) 290 && ((*type == _C_PTR && find_bs_cf_type_by_encoding(type) == NULL) 291 || *type == _C_ARY_B)) { 292 struct bsArg *bs_arg; 293 294 bs_arg = find_bs_arg_by_index(call_entry, i, expected_argc); 295 if (bs_arg == NULL || bs_arg->type_modifier == bsTypeModifierOut) 296 pointers_args[pointers_args_count++] = i; 297 } 298 } 299 FFI_LOG("detected %d omitted pointer(s)", pointers_args_count); 300 if (pointers_args_count + given_argc != expected_argc) 301 return rb_err_new(rb_eArgError, 302 "wrong number of argument(s) (expected %d, got %d)", expected_argc, 303 given_argc); 304 } 305 306 for (i = skipped = 0; i < expected_argc; i++) { 307 const char *octype_str; 308 309 octype_str = ARG_OCTYPESTR(i); 310 // C-array-length-like argument, which should be already defined 311 // at the same time than the C-array-like argument, unless it's 312 // returned by reference or specifically provided. 313 if (IS_LENGTH_ARG(i) && *octype_str != _C_PTR) { 314 if (given_argc + skipped < expected_argc) { 315 skipped++; 316 } 317 else { 318 VALUE arg; 319 int *value; 320 int *prev_len; 321 322 arg = argv[i - skipped]; 323 Check_Type(arg, T_FIXNUM); 324 325 value = OCDATA_ALLOCA(octype_str); 326 if (!rbobj_to_ocdata(arg, octype_str, value, NO)) 327 return rb_err_new(ocdataconv_err_class(), "Cannot convert the argument #%d as '%s' to Objective-C", i, octype_str); 328 329 prev_len = arg_values[i + argc_delta]; 330 if (prev_len != NULL && (*prev_len < *value || *value < 0)) 331 return rb_err_new(rb_eArgError, "Incorrect array length of argument #%d (expected a non negative value greater or equal to %d, got %d)", i, *prev_len, *value); 332 333 arg_types[i + argc_delta] = ffi_type_for_octype(octype_str); 334 arg_values[i + argc_delta] = value; 335 } 336 } 337 // Omitted pointer. 338 else if (IS_POINTER_ARG(i)) { 339 void *value; 340 arg_types[i + argc_delta] = &ffi_type_pointer; 341 if (*octype_str == _C_PTR) { 342 // Regular pointer. 343 value = alloca(sizeof(void *)); 344 *(void **)value = OCDATA_ALLOCA(octype_str+1); 345 } 346 else { 347 // C_ARY. 348 value = alloca(sizeof(void *)); 349 *(void **)value = OCDATA_ALLOCA(octype_str); 350 } 351 void **p = *(void ***)value; 352 *p = NULL; 353 arg_values[i + argc_delta] = value; 354 FFI_LOG("omitted_pointer[%d] (%p) : %s", i, arg_values[i + argc_delta], 355 octype_str); 356 skipped++; 357 } 358 // Regular argument. 359 else { 360 volatile VALUE arg; 361 void *value; 362 BOOL is_c_array; 363 int len; 364 struct bsArg *bs_arg; 365 366 arg = argv[i - skipped]; 367 bs_arg = find_bs_arg_by_index(call_entry, i, expected_argc); 368 369 if (bs_arg != NULL) { 370 if (!bs_arg->null_accepted && NIL_P(arg)) 371 return rb_err_new(rb_eArgError, "Argument #%d cannot be nil", i); 372 if (bs_arg->octypestr != NULL) 373 octype_str = bs_arg->octypestr; 374 is_c_array = bs_arg->c_ary_type != bsCArrayArgUndefined; 375 } 376 else { 377 is_c_array = NO; 378 } 379 380 // C-array-like argument. 381 if (is_c_array) { 382 const char * ptype; 383 384 ptype = octype_str; 385 ptype = encoding_skip_qualifiers(ptype); 386 if (*ptype != _C_PTR && *ptype != _C_ARY_B && *ptype != _C_CHARPTR) 387 return rb_err_new(rb_eRuntimeError, "Internal error: argument #%d is not a defined as a pointer in the runtime or it is described as such in the metadata", i); 388 ptype++; 389 390 if (NIL_P(arg)) 391 len = 0; 392 else if (TYPE(arg) == T_STRING) 393 len = RSTRING(arg)->len; 394 else if (TYPE(arg) == T_ARRAY) 395 len = RARRAY(arg)->len; // XXX should be RARRAY(arg)->len * ocdata_sizeof(...) 396 else if (rb_obj_is_kind_of(arg, objcptr_s_class())) 397 len = objcptr_allocated_size(arg); 398 else { 399 return rb_err_new(rb_eArgError, "Expected either String/Array/ObjcPtr for argument #%d (but got %s).", i, rb_obj_classname(arg)); 400 } 401 402 if (bs_arg->c_ary_type == bsCArrayArgFixedLength) { 403 int expected_len = bs_arg->c_ary_type_value * ocdata_size(ptype); 404 if (expected_len != len) 405 return rb_err_new(rb_eArgError, "Argument #%d has an invalid length (expected %d, got %d)", i, expected_len, len); 406 } 407 else if (bs_arg->c_ary_type == bsCArrayArgDelimitedByArg) { 408 int * prev_len; 409 410 prev_len = arg_values[bs_arg->c_ary_type_value + argc_delta]; 411 if (prev_len != NULL && (*prev_len > len || *prev_len < 0)) 412 return rb_err_new(rb_eArgError, "Incorrect array length of argument #%d (expected a non negative value greater or equal to %d, got %d)", i, len, *prev_len); 413 FFI_LOG("arg[%d] (%p) : %s (defined as a C array delimited by arg #%d in the metadata)", i, arg, octype_str, bs_arg->c_ary_type_value); 414 } 415 value = OCDATA_ALLOCA(octype_str); 416 if (len > 0) 417 *(void **) value = alloca(ocdata_size(ptype) * len); 418 } 419 // Regular argument. 420 else { 421 FFI_LOG("arg[%d] (%p) : %s", i, arg, octype_str); 422 len = 0; 423 value = OCDATA_ALLOCA(octype_str); 424 } 425 426 if (!rbobj_to_ocdata(arg, octype_str, value, NO)) 427 return rb_err_new(ocdataconv_err_class(), "Cannot convert the argument #%d as '%s' to Objective-C", i, octype_str); 428 429 // Register the selector value as an informal protocol, based on the metadata annotation. 430 if (*octype_str == _C_SEL && bs_arg != NULL && bs_arg->sel_of_type != NULL && *(char **)value != NULL) { 431 struct bsInformalProtocolMethod * inf_prot_method; 432 433 inf_prot_method = find_bs_informal_protocol_method(*(char **)value, NO); 434 if (inf_prot_method != NULL) { 435 if (strcmp(inf_prot_method->encoding, bs_arg->sel_of_type) != 0) 436 return rb_err_new(ocdataconv_err_class(), "Cannot register the given selector '%s' as an informal protocol method of type '%s', because another informal protocol method is already registered with the same signature (but with another type, '%s'. Please rename your selector.", *(char **)value, bs_arg->sel_of_type, inf_prot_method->encoding); 437 } 438 else { 439 inf_prot_method = (struct bsInformalProtocolMethod *)malloc(sizeof(struct bsInformalProtocolMethod)); 440 ASSERT_ALLOC(inf_prot_method); 441 inf_prot_method->selector = *(char **)value; // no need to dup it, selectors are unique 442 inf_prot_method->is_class_method = NO; 443 inf_prot_method->encoding = bs_arg->sel_of_type; 444 inf_prot_method->protocol_name = NULL; // unnamed 445 register_bs_informal_protocol_method(inf_prot_method); 446 FFI_LOG("registered informal protocol method '%s' of type '%s'", *(char **)value, bs_arg->sel_of_type); 447 } 448 } 449 450 arg_types[i + argc_delta] = ffi_type_for_octype(octype_str); 451 arg_values[i + argc_delta] = value; 452 453 if (is_c_array && bs_arg->c_ary_type == bsCArrayArgDelimitedByArg) { 454 int * plen; 455 456 FFI_LOG("arg[%d] defined as the array length (%d)", bs_arg->c_ary_type_value, len); 457 plen = (int *) alloca(sizeof(int)); 458 *plen = len; 459 arg_values[bs_arg->c_ary_type_value + argc_delta] = plen; 460 arg_types[bs_arg->c_ary_type_value + argc_delta] = &ffi_type_uint; 461 } 462 } 463 } 464 465 // Prepare return type/val. 466 if (call_entry != NULL 467 && call_entry->retval != NULL 468 && call_entry->retval->octypestr != NULL 469 && strcmp(call_entry->retval->octypestr, ret_octype) != 0) { 470 471 FFI_LOG("coercing result from octype '%s' to octype '%s'", ret_octype, call_entry->retval->octypestr); 472 ret_octype = call_entry->retval->octypestr; 473 } 474 FFI_LOG("retval : %s", ret_octype); 475 ret_type = ffi_type_for_octype(ret_octype); 476 if (ret_type != &ffi_type_void) { 477 size_t ret_len = MAX(sizeof(long), ocdata_size(ret_octype)); 478 FFI_LOG("allocated %ld bytes for the result", ret_len); 479 retval = alloca(ret_len); 480 } 481 482 // Prepare cif. 483 int cif_ret_status = ffi_prep_cif(&cif, FFI_DEFAULT_ABI, expected_argc + argc_delta, ret_type, arg_types); 484 if (cif_ret_status != FFI_OK) 485 rb_fatal("Can't prepare the cif"); 486 487 // Call function. 488 exception = Qnil; 489 @try { 490 FFI_LOG("ffi_call %p with %d args", func_sym, expected_argc + argc_delta); 491 ffi_call(&cif, FFI_FN(func_sym), (ffi_arg *)retval, arg_values); 492 FFI_LOG("ffi_call done"); 493 } 494 @catch (id oc_exception) { 495 FFI_LOG("got objc exception '%@' -- forwarding...", oc_exception); 496 exception = oc_err_new(oc_exception); 497 } 498 499 // Return exception if catched. 500 if (!NIL_P(exception)) 501 return exception; 502 503 // Get result as argument. 504 for (i = 0; i < expected_argc; i++) { 505 VALUE arg; 506 507 arg = (i < given_argc) ? argv[i] : Qnil; 508 if (arg == Qnil) 509 continue; 510 if (!is_id_ptr(ARG_OCTYPESTR(i))) 511 continue; 512 if (rb_obj_is_kind_of(arg, objid_s_class()) != Qtrue) 513 continue; 514 FFI_LOG("got passed-by-reference argument %d", i); 515 (*retain_if_necessary)(arg, NO, retain_if_necessary_ctx); 516 } 517 518 // Get result 519 if (ret_type != &ffi_type_void) { 520 FFI_LOG("getting return value (%p of type '%s')", retval, ret_octype); 521 522 if (!ocdata_to_rbobj(Qnil, ret_octype, retval, result, YES)) 523 return rb_err_new(ocdataconv_err_class(), "Cannot convert the result as '%s' to Ruby", ret_octype); 524 525 FFI_LOG("got return value"); 526 (*retain_if_necessary)(*result, YES, retain_if_necessary_ctx); 527 } 528 else { 529 *result = Qnil; 530 } 531 532 // Get omitted pointers result, and pack them with the result in an array. 533 if (pointers_args_count > 0) { 534 volatile VALUE retval_ary; 535 536 retval_ary = rb_ary_new(); 537 if (*ret_octype != _C_VOID) { 538 // Don't test if *result is nil, as nil may have been returned! 539 rb_ary_push(retval_ary, *result); 540 } 541 542 for (i = 0; i < expected_argc; i++) { 543 void *value; 544 545 if (!IS_POINTER_ARG(i)) 546 continue; 547 548 value = arg_values[i + argc_delta]; 549 if (value != NULL) { 550 volatile VALUE rbval; 551 const char *octype_str; 552 struct bsArg *bs_arg; 553 char fake_octype_str[512]; 554 555 octype_str = ARG_OCTYPESTR(i); 556 octype_str = encoding_skip_qualifiers(octype_str); 557 if (*octype_str == _C_PTR) 558 octype_str++; 559 octype_str = encoding_skip_qualifiers(octype_str); 560 FFI_LOG("got omitted_pointer[%d] : %s (%p)", i, octype_str, value); 561 rbval = Qnil; 562 if ((*octype_str == _C_PTR || *octype_str == _C_ARY_B) 563 && (bs_arg = find_bs_arg_by_index(call_entry, i, expected_argc)) 564 != NULL) { 565 566 switch (bs_arg->c_ary_type) { 567 case bsCArrayArgDelimitedByArg: 568 { 569 void *length_data; 570 long length_value; 571 572 length_data = 573 arg_values[bs_arg->c_ary_type_value + argc_delta]; 574 if (length_data == NULL) { 575 length_value = 0; 576 } 577 else if (IS_POINTER_ARG(bs_arg->c_ary_type_value)) { 578 long *p = *(long **)length_data; 579 length_value = *p; 580 } 581 else { 582 length_value = *(long *)length_data; 583 } 584 585 if (length_value > 0) { 586 if (*octype_str == _C_ARY_B) { 587 char *p = (char *)octype_str; 588 do { p++; } while (isdigit(*p)); 589 snprintf(fake_octype_str, sizeof fake_octype_str, 590 "[%ld%s", length_value, p); 591 octype_str = fake_octype_str; 592 } 593 else { 594 rbval = rb_str_new((char *)value, 595 length_value * ocdata_size(octype_str)); 596 } 597 } 598 else { 599 FFI_LOG("array length should have been returned by argument #%d, but it's invalid (%ld), defaulting on ObjCPtr", bs_arg->c_ary_type_value, length_value); 600 } 601 } 602 break; 603 604 case bsCArrayArgFixedLength: 605 rbval = rb_str_new((char *)value, bs_arg->c_ary_type_value); 606 break; 607 608 case bsCArrayArgDelimitedByNull: 609 rbval = rb_str_new2((char *)value); 610 break; 611 612 default: 613 // Do nothing. 614 break; 615 } 616 } 617 618 if (NIL_P(rbval)) { 619 void *p; 620 if (*octype_str == _C_ARY_B) 621 p = &value; 622 else 623 p = *(void **)value; 624 if (!ocdata_to_rbobj(Qnil, octype_str, p, (VALUE*)&rbval, YES)) 625 return rb_err_new(ocdataconv_err_class(), "Cannot convert the passed-by-reference argument #%d as '%s' to Ruby", i, octype_str); 626 } 627 (*retain_if_necessary)(rbval, NO, retain_if_necessary_ctx); 628 rb_ary_push(retval_ary, rbval); 629 } 630 else { 631 FFI_LOG("omitted pointer[%d] is nil, skipping...", i); 632 } 633 } 634 635 *result = RARRAY(retval_ary)->len == 1 ? RARRAY(retval_ary)->ptr[0] : RARRAY(retval_ary)->len == 0 ? Qnil : retval_ary; 636 } 637 638 FFI_LOG("ffi dispatch done"); 639 640 return Qnil; 641} 642 643void * 644ffi_make_closure(const char *rettype, const char **argtypes, unsigned argc, void (*handler)(ffi_cif *,void *,void **,void *), void *context) 645{ 646 const char *error; 647 unsigned i; 648 ffi_type *retval_ffi_type; 649 ffi_type **arg_ffi_types; 650 ffi_cif *cif; 651 ffi_closure *closure; 652 653 error = NULL; 654 cif = NULL; 655 closure = NULL; 656 657 FFI_LOG("make closure argc %d", argc); 658 659 arg_ffi_types = (ffi_type **)malloc(sizeof(ffi_type *) * (argc + 1)); 660 if (arg_ffi_types == NULL) { 661 error = "Can't allocate memory"; 662 goto bails; 663 } 664 665 for (i = 0; i < argc; i++) { 666 arg_ffi_types[i] = ffi_type_for_octype(argtypes[i]); 667 FFI_LOG("arg[%d] -> ffi_type %p", i, arg_ffi_types[i]); 668 } 669 retval_ffi_type = ffi_type_for_octype(rettype); 670 arg_ffi_types[argc] = NULL; 671 672 cif = (ffi_cif *)malloc(sizeof(ffi_cif)); 673 if (cif == NULL) { 674 error = "Can't allocate memory"; 675 goto bails; 676 } 677 678 if (ffi_prep_cif(cif, FFI_DEFAULT_ABI, argc, retval_ffi_type, arg_ffi_types) != FFI_OK) { 679 error = "Can't prepare cif"; 680 goto bails; 681 } 682 683 // Allocate a page to hold the closure with read and write permissions. 684 if ((closure = mmap(NULL, sizeof(ffi_closure), PROT_READ | PROT_WRITE, 685 MAP_ANON | MAP_PRIVATE, -1, 0)) == (void*)-1) 686 { 687 error = "Can't allocate memory"; 688 goto bails; 689 } 690 691 if (ffi_prep_closure(closure, cif, handler, context) != FFI_OK) { 692 error = "Can't prepare closure"; 693 goto bails; 694 } 695 696 // Ensure that the closure will execute on all architectures. 697 if (mprotect(closure, sizeof(closure), PROT_READ | PROT_EXEC) == -1) 698 { 699 error = "Can't mark the closure with PROT_EXEC"; 700 goto bails; 701 } 702 703 goto done; 704 705bails: 706 if (arg_ffi_types != NULL) 707 free(arg_ffi_types); 708 if (cif != NULL) 709 free(cif); 710 if (closure != NULL) 711 free(closure); 712 if (error != NULL) 713 rb_raise(rb_eRuntimeError, error); 714 715done: 716 return closure; 717} 718 719@interface __OVMIXThreadDispatcher : NSObject 720{ 721 void (*_handler)(ffi_cif *,void *,void **,void *); 722 void (*_finished_handler)(ffi_cif *,void *,void **,void *); 723 ffi_cif * _cif; 724 void * _resp; 725 void ** _args; 726 void * _userdata; 727} 728@end 729 730@implementation __OVMIXThreadDispatcher 731 732- (id)initWithClosure:(void (*)(ffi_cif *,void *,void **,void *))handler 733 cif:(ffi_cif *)cif 734 resp:(void *)resp 735 args:(void **)args 736 userdata:(void *)userdata 737 finished_handler:(void (*)(ffi_cif *,void *,void **,void *))finished_handler 738{ 739 self = [super init]; 740 if (self != NULL) { 741 _handler = handler; 742 _cif = cif; 743 _resp = resp; 744 _args = args; 745 _userdata = userdata; 746 _finished_handler = finished_handler; 747 } 748 return self; 749} 750 751extern NSThread *rubycocoaThread; 752 753- (void)dispatch 754{ 755 DISPATCH_ON_RUBYCOCOA_THREAD(self, @selector(syncDispatch)); 756} 757 758- (void)syncDispatch 759{ 760 (*_handler)(_cif, _resp, _args, _userdata); 761 (*_finished_handler)(_cif, _resp, _args, _userdata); 762} 763 764@end 765 766void ffi_dispatch_closure_in_main_thread( 767 void (*handler)(ffi_cif *,void *,void **,void *), 768 ffi_cif *cif, 769 void *resp, 770 void **args, 771 void *userdata, 772 void (*finished_handler)(ffi_cif *,void *,void **,void *)) 773{ 774 __OVMIXThreadDispatcher * dispatcher; 775 776 dispatcher = [[__OVMIXThreadDispatcher alloc] 777 initWithClosure:handler 778 cif:cif 779 resp:resp 780 args:args 781 userdata:userdata 782 finished_handler:finished_handler]; 783 [dispatcher dispatch]; 784 [dispatcher release]; 785} 786