github.com/prattmic/llgo-embedded@v0.0.0-20150820070356-41cfecea0e1e/third_party/gofrontend/libffi/src/arm/ffi.c (about) 1 /* ----------------------------------------------------------------------- 2 ffi.c - Copyright (c) 2011 Timothy Wall 3 Copyright (c) 2011 Plausible Labs Cooperative, Inc. 4 Copyright (c) 2011 Anthony Green 5 Copyright (c) 2011 Free Software Foundation 6 Copyright (c) 1998, 2008, 2011 Red Hat, Inc. 7 8 ARM Foreign Function Interface 9 10 Permission is hereby granted, free of charge, to any person obtaining 11 a copy of this software and associated documentation files (the 12 ``Software''), to deal in the Software without restriction, including 13 without limitation the rights to use, copy, modify, merge, publish, 14 distribute, sublicense, and/or sell copies of the Software, and to 15 permit persons to whom the Software is furnished to do so, subject to 16 the following conditions: 17 18 The above copyright notice and this permission notice shall be included 19 in all copies or substantial portions of the Software. 20 21 THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, 22 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 23 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 24 NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 25 HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 26 WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 27 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 28 DEALINGS IN THE SOFTWARE. 29 ----------------------------------------------------------------------- */ 30 31 #include <ffi.h> 32 #include <ffi_common.h> 33 #include <stdlib.h> 34 #include "internal.h" 35 36 /* Forward declares. */ 37 static int vfp_type_p (const ffi_type *); 38 static void layout_vfp_args (ffi_cif *); 39 40 static void * 41 ffi_align (ffi_type *ty, void *p) 42 { 43 /* Align if necessary */ 44 size_t alignment; 45 #ifdef _WIN32_WCE 46 alignment = 4; 47 #else 48 alignment = ty->alignment; 49 if (alignment < 4) 50 alignment = 4; 51 #endif 52 return (void *) ALIGN (p, alignment); 53 } 54 55 static size_t 56 ffi_put_arg (ffi_type *ty, void *src, void *dst) 57 { 58 size_t z = ty->size; 59 60 switch (ty->type) 61 { 62 case FFI_TYPE_SINT8: 63 *(UINT32 *)dst = *(SINT8 *)src; 64 break; 65 case FFI_TYPE_UINT8: 66 *(UINT32 *)dst = *(UINT8 *)src; 67 break; 68 case FFI_TYPE_SINT16: 69 *(UINT32 *)dst = *(SINT16 *)src; 70 break; 71 case FFI_TYPE_UINT16: 72 *(UINT32 *)dst = *(UINT16 *)src; 73 break; 74 75 case FFI_TYPE_INT: 76 case FFI_TYPE_SINT32: 77 case FFI_TYPE_UINT32: 78 case FFI_TYPE_POINTER: 79 case FFI_TYPE_FLOAT: 80 *(UINT32 *)dst = *(UINT32 *)src; 81 break; 82 83 case FFI_TYPE_SINT64: 84 case FFI_TYPE_UINT64: 85 case FFI_TYPE_DOUBLE: 86 *(UINT64 *)dst = *(UINT64 *)src; 87 break; 88 89 case FFI_TYPE_STRUCT: 90 case FFI_TYPE_COMPLEX: 91 memcpy (dst, src, z); 92 break; 93 94 default: 95 abort(); 96 } 97 98 return ALIGN (z, 4); 99 } 100 101 /* ffi_prep_args is called once stack space has been allocated 102 for the function's arguments. 103 104 The vfp_space parameter is the load area for VFP regs, the return 105 value is cif->vfp_used (word bitset of VFP regs used for passing 106 arguments). These are only used for the VFP hard-float ABI. 107 */ 108 static void 109 ffi_prep_args_SYSV (ffi_cif *cif, int flags, void *rvalue, 110 void **avalue, char *argp) 111 { 112 ffi_type **arg_types = cif->arg_types; 113 int i, n; 114 115 if (flags == ARM_TYPE_STRUCT) 116 { 117 *(void **) argp = rvalue; 118 argp += 4; 119 } 120 121 for (i = 0, n = cif->nargs; i < n; i++) 122 { 123 ffi_type *ty = arg_types[i]; 124 argp = ffi_align (ty, argp); 125 argp += ffi_put_arg (ty, avalue[i], argp); 126 } 127 } 128 129 static void 130 ffi_prep_args_VFP (ffi_cif *cif, int flags, void *rvalue, 131 void **avalue, char *stack, char *vfp_space) 132 { 133 ffi_type **arg_types = cif->arg_types; 134 int i, n, vi = 0; 135 char *argp, *regp, *eo_regp; 136 char stack_used = 0; 137 char done_with_regs = 0; 138 139 /* The first 4 words on the stack are used for values 140 passed in core registers. */ 141 regp = stack; 142 eo_regp = argp = regp + 16; 143 144 /* If the function returns an FFI_TYPE_STRUCT in memory, 145 that address is passed in r0 to the function. */ 146 if (flags == ARM_TYPE_STRUCT) 147 { 148 *(void **) regp = rvalue; 149 regp += 4; 150 } 151 152 for (i = 0, n = cif->nargs; i < n; i++) 153 { 154 ffi_type *ty = arg_types[i]; 155 void *a = avalue[i]; 156 int is_vfp_type = vfp_type_p (ty); 157 158 /* Allocated in VFP registers. */ 159 if (vi < cif->vfp_nargs && is_vfp_type) 160 { 161 char *vfp_slot = vfp_space + cif->vfp_args[vi++] * 4; 162 ffi_put_arg (ty, a, vfp_slot); 163 continue; 164 } 165 /* Try allocating in core registers. */ 166 else if (!done_with_regs && !is_vfp_type) 167 { 168 char *tregp = ffi_align (ty, regp); 169 size_t size = ty->size; 170 size = (size < 4) ? 4 : size; // pad 171 /* Check if there is space left in the aligned register 172 area to place the argument. */ 173 if (tregp + size <= eo_regp) 174 { 175 regp = tregp + ffi_put_arg (ty, a, tregp); 176 done_with_regs = (regp == argp); 177 // ensure we did not write into the stack area 178 FFI_ASSERT (regp <= argp); 179 continue; 180 } 181 /* In case there are no arguments in the stack area yet, 182 the argument is passed in the remaining core registers 183 and on the stack. */ 184 else if (!stack_used) 185 { 186 stack_used = 1; 187 done_with_regs = 1; 188 argp = tregp + ffi_put_arg (ty, a, tregp); 189 FFI_ASSERT (eo_regp < argp); 190 continue; 191 } 192 } 193 /* Base case, arguments are passed on the stack */ 194 stack_used = 1; 195 argp = ffi_align (ty, argp); 196 argp += ffi_put_arg (ty, a, argp); 197 } 198 } 199 200 /* Perform machine dependent cif processing */ 201 ffi_status 202 ffi_prep_cif_machdep (ffi_cif *cif) 203 { 204 int flags = 0, cabi = cif->abi; 205 size_t bytes = cif->bytes; 206 207 /* Map out the register placements of VFP register args. The VFP 208 hard-float calling conventions are slightly more sophisticated 209 than the base calling conventions, so we do it here instead of 210 in ffi_prep_args(). */ 211 if (cabi == FFI_VFP) 212 layout_vfp_args (cif); 213 214 /* Set the return type flag */ 215 switch (cif->rtype->type) 216 { 217 case FFI_TYPE_VOID: 218 flags = ARM_TYPE_VOID; 219 break; 220 221 case FFI_TYPE_INT: 222 case FFI_TYPE_UINT8: 223 case FFI_TYPE_SINT8: 224 case FFI_TYPE_UINT16: 225 case FFI_TYPE_SINT16: 226 case FFI_TYPE_UINT32: 227 case FFI_TYPE_SINT32: 228 case FFI_TYPE_POINTER: 229 flags = ARM_TYPE_INT; 230 break; 231 232 case FFI_TYPE_SINT64: 233 case FFI_TYPE_UINT64: 234 flags = ARM_TYPE_INT64; 235 break; 236 237 case FFI_TYPE_FLOAT: 238 flags = (cabi == FFI_VFP ? ARM_TYPE_VFP_S : ARM_TYPE_INT); 239 break; 240 case FFI_TYPE_DOUBLE: 241 flags = (cabi == FFI_VFP ? ARM_TYPE_VFP_D : ARM_TYPE_INT64); 242 break; 243 244 case FFI_TYPE_STRUCT: 245 case FFI_TYPE_COMPLEX: 246 if (cabi == FFI_VFP) 247 { 248 int h = vfp_type_p (cif->rtype); 249 250 flags = ARM_TYPE_VFP_N; 251 if (h == 0x100 + FFI_TYPE_FLOAT) 252 flags = ARM_TYPE_VFP_S; 253 if (h == 0x100 + FFI_TYPE_DOUBLE) 254 flags = ARM_TYPE_VFP_D; 255 if (h != 0) 256 break; 257 } 258 259 /* A Composite Type not larger than 4 bytes is returned in r0. 260 A Composite Type larger than 4 bytes, or whose size cannot 261 be determined statically ... is stored in memory at an 262 address passed [in r0]. */ 263 if (cif->rtype->size <= 4) 264 flags = ARM_TYPE_INT; 265 else 266 { 267 flags = ARM_TYPE_STRUCT; 268 bytes += 4; 269 } 270 break; 271 272 default: 273 abort(); 274 } 275 276 /* Round the stack up to a multiple of 8 bytes. This isn't needed 277 everywhere, but it is on some platforms, and it doesn't harm anything 278 when it isn't needed. */ 279 bytes = ALIGN (bytes, 8); 280 281 /* Minimum stack space is the 4 register arguments that we pop. */ 282 if (bytes < 4*4) 283 bytes = 4*4; 284 285 cif->bytes = bytes; 286 cif->flags = flags; 287 288 return FFI_OK; 289 } 290 291 /* Perform machine dependent cif processing for variadic calls */ 292 ffi_status 293 ffi_prep_cif_machdep_var (ffi_cif * cif, 294 unsigned int nfixedargs, unsigned int ntotalargs) 295 { 296 /* VFP variadic calls actually use the SYSV ABI */ 297 if (cif->abi == FFI_VFP) 298 cif->abi = FFI_SYSV; 299 300 return ffi_prep_cif_machdep (cif); 301 } 302 303 /* Prototypes for assembly functions, in sysv.S. */ 304 305 struct call_frame 306 { 307 void *fp; 308 void *lr; 309 void *rvalue; 310 int flags; 311 void *closure; 312 }; 313 314 extern void ffi_call_SYSV (void *stack, struct call_frame *, 315 void (*fn) (void)) FFI_HIDDEN; 316 extern void ffi_call_VFP (void *vfp_space, struct call_frame *, 317 void (*fn) (void), unsigned vfp_used) FFI_HIDDEN; 318 319 static void 320 ffi_call_int (ffi_cif * cif, void (*fn) (void), void *rvalue, 321 void **avalue, void *closure) 322 { 323 int flags = cif->flags; 324 ffi_type *rtype = cif->rtype; 325 size_t bytes, rsize, vfp_size; 326 char *stack, *vfp_space, *new_rvalue; 327 struct call_frame *frame; 328 329 rsize = 0; 330 if (rvalue == NULL) 331 { 332 /* If the return value is a struct and we don't have a return 333 value address then we need to make one. Otherwise the return 334 value is in registers and we can ignore them. */ 335 if (flags == ARM_TYPE_STRUCT) 336 rsize = rtype->size; 337 else 338 flags = ARM_TYPE_VOID; 339 } 340 else if (flags == ARM_TYPE_VFP_N) 341 { 342 /* Largest case is double x 4. */ 343 rsize = 32; 344 } 345 else if (flags == ARM_TYPE_INT && rtype->type == FFI_TYPE_STRUCT) 346 rsize = 4; 347 348 /* Largest case. */ 349 vfp_size = (cif->abi == FFI_VFP && cif->vfp_used ? 8*8: 0); 350 351 bytes = cif->bytes; 352 stack = alloca (vfp_size + bytes + sizeof(struct call_frame) + rsize); 353 354 vfp_space = NULL; 355 if (vfp_size) 356 { 357 vfp_space = stack; 358 stack += vfp_size; 359 } 360 361 frame = (struct call_frame *)(stack + bytes); 362 363 new_rvalue = rvalue; 364 if (rsize) 365 new_rvalue = (void *)(frame + 1); 366 367 frame->rvalue = new_rvalue; 368 frame->flags = flags; 369 frame->closure = closure; 370 371 if (vfp_space) 372 { 373 ffi_prep_args_VFP (cif, flags, new_rvalue, avalue, stack, vfp_space); 374 ffi_call_VFP (vfp_space, frame, fn, cif->vfp_used); 375 } 376 else 377 { 378 ffi_prep_args_SYSV (cif, flags, new_rvalue, avalue, stack); 379 ffi_call_SYSV (stack, frame, fn); 380 } 381 382 if (rvalue && rvalue != new_rvalue) 383 memcpy (rvalue, new_rvalue, rtype->size); 384 } 385 386 void 387 ffi_call (ffi_cif *cif, void (*fn) (void), void *rvalue, void **avalue) 388 { 389 ffi_call_int (cif, fn, rvalue, avalue, NULL); 390 } 391 392 void 393 ffi_call_go (ffi_cif *cif, void (*fn) (void), void *rvalue, 394 void **avalue, void *closure) 395 { 396 ffi_call_int (cif, fn, rvalue, avalue, closure); 397 } 398 399 static void * 400 ffi_prep_incoming_args_SYSV (ffi_cif *cif, void *rvalue, 401 char *argp, void **avalue) 402 { 403 ffi_type **arg_types = cif->arg_types; 404 int i, n; 405 406 if (cif->flags == ARM_TYPE_STRUCT) 407 { 408 rvalue = *(void **) argp; 409 argp += 4; 410 } 411 412 for (i = 0, n = cif->nargs; i < n; i++) 413 { 414 ffi_type *ty = arg_types[i]; 415 size_t z = ty->size; 416 417 argp = ffi_align (ty, argp); 418 avalue[i] = (void *) argp; 419 argp += z; 420 } 421 422 return rvalue; 423 } 424 425 static void * 426 ffi_prep_incoming_args_VFP (ffi_cif *cif, void *rvalue, char *stack, 427 char *vfp_space, void **avalue) 428 { 429 ffi_type **arg_types = cif->arg_types; 430 int i, n, vi = 0; 431 char *argp, *regp, *eo_regp; 432 char done_with_regs = 0; 433 char stack_used = 0; 434 435 regp = stack; 436 eo_regp = argp = regp + 16; 437 438 if (cif->flags == ARM_TYPE_STRUCT) 439 { 440 rvalue = *(void **) regp; 441 regp += 4; 442 } 443 444 for (i = 0, n = cif->nargs; i < n; i++) 445 { 446 ffi_type *ty = arg_types[i]; 447 int is_vfp_type = vfp_type_p (ty); 448 size_t z = ty->size; 449 450 if (vi < cif->vfp_nargs && is_vfp_type) 451 { 452 avalue[i] = vfp_space + cif->vfp_args[vi++] * 4; 453 continue; 454 } 455 else if (!done_with_regs && !is_vfp_type) 456 { 457 char *tregp = ffi_align (ty, regp); 458 459 z = (z < 4) ? 4 : z; // pad 460 461 /* If the arguments either fits into the registers or uses registers 462 and stack, while we haven't read other things from the stack */ 463 if (tregp + z <= eo_regp || !stack_used) 464 { 465 /* Because we're little endian, this is what it turns into. */ 466 avalue[i] = (void *) tregp; 467 regp = tregp + z; 468 469 /* If we read past the last core register, make sure we 470 have not read from the stack before and continue 471 reading after regp. */ 472 if (regp > eo_regp) 473 { 474 FFI_ASSERT (!stack_used); 475 argp = regp; 476 } 477 if (regp >= eo_regp) 478 { 479 done_with_regs = 1; 480 stack_used = 1; 481 } 482 continue; 483 } 484 } 485 486 stack_used = 1; 487 argp = ffi_align (ty, argp); 488 avalue[i] = (void *) argp; 489 argp += z; 490 } 491 492 return rvalue; 493 } 494 495 struct closure_frame 496 { 497 char vfp_space[8*8] __attribute__((aligned(8))); 498 char result[8*4]; 499 char argp[]; 500 }; 501 502 int FFI_HIDDEN 503 ffi_closure_inner_SYSV (ffi_cif *cif, 504 void (*fun) (ffi_cif *, void *, void **, void *), 505 void *user_data, 506 struct closure_frame *frame) 507 { 508 void **avalue = (void **) alloca (cif->nargs * sizeof (void *)); 509 void *rvalue = ffi_prep_incoming_args_SYSV (cif, frame->result, 510 frame->argp, avalue); 511 fun (cif, rvalue, avalue, user_data); 512 return cif->flags; 513 } 514 515 int FFI_HIDDEN 516 ffi_closure_inner_VFP (ffi_cif *cif, 517 void (*fun) (ffi_cif *, void *, void **, void *), 518 void *user_data, 519 struct closure_frame *frame) 520 { 521 void **avalue = (void **) alloca (cif->nargs * sizeof (void *)); 522 void *rvalue = ffi_prep_incoming_args_VFP (cif, frame->result, frame->argp, 523 frame->vfp_space, avalue); 524 fun (cif, rvalue, avalue, user_data); 525 return cif->flags; 526 } 527 528 void ffi_closure_SYSV (void) FFI_HIDDEN; 529 void ffi_closure_VFP (void) FFI_HIDDEN; 530 void ffi_go_closure_SYSV (void) FFI_HIDDEN; 531 void ffi_go_closure_VFP (void) FFI_HIDDEN; 532 533 #if FFI_EXEC_TRAMPOLINE_TABLE 534 535 #include <mach/mach.h> 536 #include <pthread.h> 537 #include <stdio.h> 538 #include <stdlib.h> 539 540 extern void *ffi_closure_trampoline_table_page; 541 542 typedef struct ffi_trampoline_table ffi_trampoline_table; 543 typedef struct ffi_trampoline_table_entry ffi_trampoline_table_entry; 544 545 struct ffi_trampoline_table 546 { 547 /* contiguous writable and executable pages */ 548 vm_address_t config_page; 549 vm_address_t trampoline_page; 550 551 /* free list tracking */ 552 uint16_t free_count; 553 ffi_trampoline_table_entry *free_list; 554 ffi_trampoline_table_entry *free_list_pool; 555 556 ffi_trampoline_table *prev; 557 ffi_trampoline_table *next; 558 }; 559 560 struct ffi_trampoline_table_entry 561 { 562 void *(*trampoline) (); 563 ffi_trampoline_table_entry *next; 564 }; 565 566 /* Override the standard architecture trampoline size */ 567 // XXX TODO - Fix 568 #undef FFI_TRAMPOLINE_SIZE 569 #define FFI_TRAMPOLINE_SIZE 12 570 571 /* The trampoline configuration is placed at 4080 bytes prior to the trampoline's entry point */ 572 #define FFI_TRAMPOLINE_CODELOC_CONFIG(codeloc) ((void **) (((uint8_t *) codeloc) - 4080)); 573 574 /* The first 16 bytes of the config page are unused, as they are unaddressable from the trampoline page. */ 575 #define FFI_TRAMPOLINE_CONFIG_PAGE_OFFSET 16 576 577 /* Total number of trampolines that fit in one trampoline table */ 578 #define FFI_TRAMPOLINE_COUNT ((PAGE_SIZE - FFI_TRAMPOLINE_CONFIG_PAGE_OFFSET) / FFI_TRAMPOLINE_SIZE) 579 580 static pthread_mutex_t ffi_trampoline_lock = PTHREAD_MUTEX_INITIALIZER; 581 static ffi_trampoline_table *ffi_trampoline_tables = NULL; 582 583 static ffi_trampoline_table * 584 ffi_trampoline_table_alloc () 585 { 586 ffi_trampoline_table *table = NULL; 587 588 /* Loop until we can allocate two contiguous pages */ 589 while (table == NULL) 590 { 591 vm_address_t config_page = 0x0; 592 kern_return_t kt; 593 594 /* Try to allocate two pages */ 595 kt = 596 vm_allocate (mach_task_self (), &config_page, PAGE_SIZE * 2, 597 VM_FLAGS_ANYWHERE); 598 if (kt != KERN_SUCCESS) 599 { 600 fprintf (stderr, "vm_allocate() failure: %d at %s:%d\n", kt, 601 __FILE__, __LINE__); 602 break; 603 } 604 605 /* Now drop the second half of the allocation to make room for the trampoline table */ 606 vm_address_t trampoline_page = config_page + PAGE_SIZE; 607 kt = vm_deallocate (mach_task_self (), trampoline_page, PAGE_SIZE); 608 if (kt != KERN_SUCCESS) 609 { 610 fprintf (stderr, "vm_deallocate() failure: %d at %s:%d\n", kt, 611 __FILE__, __LINE__); 612 break; 613 } 614 615 /* Remap the trampoline table to directly follow the config page */ 616 vm_prot_t cur_prot; 617 vm_prot_t max_prot; 618 619 kt = 620 vm_remap (mach_task_self (), &trampoline_page, PAGE_SIZE, 0x0, FALSE, 621 mach_task_self (), 622 (vm_address_t) & ffi_closure_trampoline_table_page, FALSE, 623 &cur_prot, &max_prot, VM_INHERIT_SHARE); 624 625 /* If we lost access to the destination trampoline page, drop our config allocation mapping and retry */ 626 if (kt != KERN_SUCCESS) 627 { 628 /* Log unexpected failures */ 629 if (kt != KERN_NO_SPACE) 630 { 631 fprintf (stderr, "vm_remap() failure: %d at %s:%d\n", kt, 632 __FILE__, __LINE__); 633 } 634 635 vm_deallocate (mach_task_self (), config_page, PAGE_SIZE); 636 continue; 637 } 638 639 /* We have valid trampoline and config pages */ 640 table = calloc (1, sizeof (ffi_trampoline_table)); 641 table->free_count = FFI_TRAMPOLINE_COUNT; 642 table->config_page = config_page; 643 table->trampoline_page = trampoline_page; 644 645 /* Create and initialize the free list */ 646 table->free_list_pool = 647 calloc (FFI_TRAMPOLINE_COUNT, sizeof (ffi_trampoline_table_entry)); 648 649 uint16_t i; 650 for (i = 0; i < table->free_count; i++) 651 { 652 ffi_trampoline_table_entry *entry = &table->free_list_pool[i]; 653 entry->trampoline = 654 (void *) (table->trampoline_page + (i * FFI_TRAMPOLINE_SIZE)); 655 656 if (i < table->free_count - 1) 657 entry->next = &table->free_list_pool[i + 1]; 658 } 659 660 table->free_list = table->free_list_pool; 661 } 662 663 return table; 664 } 665 666 void * 667 ffi_closure_alloc (size_t size, void **code) 668 { 669 /* Create the closure */ 670 ffi_closure *closure = malloc (size); 671 if (closure == NULL) 672 return NULL; 673 674 pthread_mutex_lock (&ffi_trampoline_lock); 675 676 /* Check for an active trampoline table with available entries. */ 677 ffi_trampoline_table *table = ffi_trampoline_tables; 678 if (table == NULL || table->free_list == NULL) 679 { 680 table = ffi_trampoline_table_alloc (); 681 if (table == NULL) 682 { 683 free (closure); 684 return NULL; 685 } 686 687 /* Insert the new table at the top of the list */ 688 table->next = ffi_trampoline_tables; 689 if (table->next != NULL) 690 table->next->prev = table; 691 692 ffi_trampoline_tables = table; 693 } 694 695 /* Claim the free entry */ 696 ffi_trampoline_table_entry *entry = ffi_trampoline_tables->free_list; 697 ffi_trampoline_tables->free_list = entry->next; 698 ffi_trampoline_tables->free_count--; 699 entry->next = NULL; 700 701 pthread_mutex_unlock (&ffi_trampoline_lock); 702 703 /* Initialize the return values */ 704 *code = entry->trampoline; 705 closure->trampoline_table = table; 706 closure->trampoline_table_entry = entry; 707 708 return closure; 709 } 710 711 void 712 ffi_closure_free (void *ptr) 713 { 714 ffi_closure *closure = ptr; 715 716 pthread_mutex_lock (&ffi_trampoline_lock); 717 718 /* Fetch the table and entry references */ 719 ffi_trampoline_table *table = closure->trampoline_table; 720 ffi_trampoline_table_entry *entry = closure->trampoline_table_entry; 721 722 /* Return the entry to the free list */ 723 entry->next = table->free_list; 724 table->free_list = entry; 725 table->free_count++; 726 727 /* If all trampolines within this table are free, and at least one other table exists, deallocate 728 * the table */ 729 if (table->free_count == FFI_TRAMPOLINE_COUNT 730 && ffi_trampoline_tables != table) 731 { 732 /* Remove from the list */ 733 if (table->prev != NULL) 734 table->prev->next = table->next; 735 736 if (table->next != NULL) 737 table->next->prev = table->prev; 738 739 /* Deallocate pages */ 740 kern_return_t kt; 741 kt = vm_deallocate (mach_task_self (), table->config_page, PAGE_SIZE); 742 if (kt != KERN_SUCCESS) 743 fprintf (stderr, "vm_deallocate() failure: %d at %s:%d\n", kt, 744 __FILE__, __LINE__); 745 746 kt = 747 vm_deallocate (mach_task_self (), table->trampoline_page, PAGE_SIZE); 748 if (kt != KERN_SUCCESS) 749 fprintf (stderr, "vm_deallocate() failure: %d at %s:%d\n", kt, 750 __FILE__, __LINE__); 751 752 /* Deallocate free list */ 753 free (table->free_list_pool); 754 free (table); 755 } 756 else if (ffi_trampoline_tables != table) 757 { 758 /* Otherwise, bump this table to the top of the list */ 759 table->prev = NULL; 760 table->next = ffi_trampoline_tables; 761 if (ffi_trampoline_tables != NULL) 762 ffi_trampoline_tables->prev = table; 763 764 ffi_trampoline_tables = table; 765 } 766 767 pthread_mutex_unlock (&ffi_trampoline_lock); 768 769 /* Free the closure */ 770 free (closure); 771 } 772 773 #else 774 775 extern unsigned int ffi_arm_trampoline[2] FFI_HIDDEN; 776 777 #endif 778 779 /* the cif must already be prep'ed */ 780 781 ffi_status 782 ffi_prep_closure_loc (ffi_closure * closure, 783 ffi_cif * cif, 784 void (*fun) (ffi_cif *, void *, void **, void *), 785 void *user_data, void *codeloc) 786 { 787 void (*closure_func) (void) = ffi_closure_SYSV; 788 789 if (cif->abi == FFI_VFP) 790 { 791 /* We only need take the vfp path if there are vfp arguments. */ 792 if (cif->vfp_used) 793 closure_func = ffi_closure_VFP; 794 } 795 else if (cif->abi != FFI_SYSV) 796 return FFI_BAD_ABI; 797 798 #if FFI_EXEC_TRAMPOLINE_TABLE 799 void **config = FFI_TRAMPOLINE_CODELOC_CONFIG (codeloc); 800 config[0] = closure; 801 config[1] = closure_func; 802 #else 803 memcpy (closure->tramp, ffi_arm_trampoline, 8); 804 __clear_cache(closure->tramp, closure->tramp + 8); /* clear data map */ 805 __clear_cache(codeloc, codeloc + 8); /* clear insn map */ 806 *(void (**)(void))(closure->tramp + 8) = closure_func; 807 #endif 808 809 closure->cif = cif; 810 closure->fun = fun; 811 closure->user_data = user_data; 812 813 return FFI_OK; 814 } 815 816 ffi_status 817 ffi_prep_go_closure (ffi_go_closure *closure, ffi_cif *cif, 818 void (*fun) (ffi_cif *, void *, void **, void *)) 819 { 820 void (*closure_func) (void) = ffi_go_closure_SYSV; 821 822 if (cif->abi == FFI_VFP) 823 { 824 /* We only need take the vfp path if there are vfp arguments. */ 825 if (cif->vfp_used) 826 closure_func = ffi_go_closure_VFP; 827 } 828 else if (cif->abi != FFI_SYSV) 829 return FFI_BAD_ABI; 830 831 closure->tramp = closure_func; 832 closure->cif = cif; 833 closure->fun = fun; 834 835 return FFI_OK; 836 } 837 838 /* Below are routines for VFP hard-float support. */ 839 840 /* A subroutine of vfp_type_p. Given a structure type, return the type code 841 of the first non-structure element. Recurse for structure elements. 842 Return -1 if the structure is in fact empty, i.e. no nested elements. */ 843 844 static int 845 is_hfa0 (const ffi_type *ty) 846 { 847 ffi_type **elements = ty->elements; 848 int i, ret = -1; 849 850 if (elements != NULL) 851 for (i = 0; elements[i]; ++i) 852 { 853 ret = elements[i]->type; 854 if (ret == FFI_TYPE_STRUCT || ret == FFI_TYPE_COMPLEX) 855 { 856 ret = is_hfa0 (elements[i]); 857 if (ret < 0) 858 continue; 859 } 860 break; 861 } 862 863 return ret; 864 } 865 866 /* A subroutine of vfp_type_p. Given a structure type, return true if all 867 of the non-structure elements are the same as CANDIDATE. */ 868 869 static int 870 is_hfa1 (const ffi_type *ty, int candidate) 871 { 872 ffi_type **elements = ty->elements; 873 int i; 874 875 if (elements != NULL) 876 for (i = 0; elements[i]; ++i) 877 { 878 int t = elements[i]->type; 879 if (t == FFI_TYPE_STRUCT || t == FFI_TYPE_COMPLEX) 880 { 881 if (!is_hfa1 (elements[i], candidate)) 882 return 0; 883 } 884 else if (t != candidate) 885 return 0; 886 } 887 888 return 1; 889 } 890 891 /* Determine if TY is an homogenous floating point aggregate (HFA). 892 That is, a structure consisting of 1 to 4 members of all the same type, 893 where that type is a floating point scalar. 894 895 Returns non-zero iff TY is an HFA. The result is an encoded value where 896 bits 0-7 contain the type code, and bits 8-10 contain the element count. */ 897 898 static int 899 vfp_type_p (const ffi_type *ty) 900 { 901 ffi_type **elements; 902 int candidate, i; 903 size_t size, ele_count; 904 905 /* Quickest tests first. */ 906 candidate = ty->type; 907 switch (ty->type) 908 { 909 default: 910 return 0; 911 case FFI_TYPE_FLOAT: 912 case FFI_TYPE_DOUBLE: 913 ele_count = 1; 914 goto done; 915 case FFI_TYPE_COMPLEX: 916 candidate = ty->elements[0]->type; 917 if (candidate != FFI_TYPE_FLOAT && candidate != FFI_TYPE_DOUBLE) 918 return 0; 919 ele_count = 2; 920 goto done; 921 case FFI_TYPE_STRUCT: 922 break; 923 } 924 925 /* No HFA types are smaller than 4 bytes, or larger than 32 bytes. */ 926 size = ty->size; 927 if (size < 4 || size > 32) 928 return 0; 929 930 /* Find the type of the first non-structure member. */ 931 elements = ty->elements; 932 candidate = elements[0]->type; 933 if (candidate == FFI_TYPE_STRUCT || candidate == FFI_TYPE_COMPLEX) 934 { 935 for (i = 0; ; ++i) 936 { 937 candidate = is_hfa0 (elements[i]); 938 if (candidate >= 0) 939 break; 940 } 941 } 942 943 /* If the first member is not a floating point type, it's not an HFA. 944 Also quickly re-check the size of the structure. */ 945 switch (candidate) 946 { 947 case FFI_TYPE_FLOAT: 948 ele_count = size / sizeof(float); 949 if (size != ele_count * sizeof(float)) 950 return 0; 951 break; 952 case FFI_TYPE_DOUBLE: 953 ele_count = size / sizeof(double); 954 if (size != ele_count * sizeof(double)) 955 return 0; 956 break; 957 default: 958 return 0; 959 } 960 if (ele_count > 4) 961 return 0; 962 963 /* Finally, make sure that all scalar elements are the same type. */ 964 for (i = 0; elements[i]; ++i) 965 { 966 int t = elements[i]->type; 967 if (t == FFI_TYPE_STRUCT || t == FFI_TYPE_COMPLEX) 968 { 969 if (!is_hfa1 (elements[i], candidate)) 970 return 0; 971 } 972 else if (t != candidate) 973 return 0; 974 } 975 976 /* All tests succeeded. Encode the result. */ 977 done: 978 return (ele_count << 8) | candidate; 979 } 980 981 static int 982 place_vfp_arg (ffi_cif *cif, int h) 983 { 984 unsigned short reg = cif->vfp_reg_free; 985 int align = 1, nregs = h >> 8; 986 987 if ((h & 0xff) == FFI_TYPE_DOUBLE) 988 align = 2, nregs *= 2; 989 990 /* Align register number. */ 991 if ((reg & 1) && align == 2) 992 reg++; 993 994 while (reg + nregs <= 16) 995 { 996 int s, new_used = 0; 997 for (s = reg; s < reg + nregs; s++) 998 { 999 new_used |= (1 << s); 1000 if (cif->vfp_used & (1 << s)) 1001 { 1002 reg += align; 1003 goto next_reg; 1004 } 1005 } 1006 /* Found regs to allocate. */ 1007 cif->vfp_used |= new_used; 1008 cif->vfp_args[cif->vfp_nargs++] = reg; 1009 1010 /* Update vfp_reg_free. */ 1011 if (cif->vfp_used & (1 << cif->vfp_reg_free)) 1012 { 1013 reg += nregs; 1014 while (cif->vfp_used & (1 << reg)) 1015 reg += 1; 1016 cif->vfp_reg_free = reg; 1017 } 1018 return 0; 1019 next_reg:; 1020 } 1021 // done, mark all regs as used 1022 cif->vfp_reg_free = 16; 1023 cif->vfp_used = 0xFFFF; 1024 return 1; 1025 } 1026 1027 static void 1028 layout_vfp_args (ffi_cif * cif) 1029 { 1030 int i; 1031 /* Init VFP fields */ 1032 cif->vfp_used = 0; 1033 cif->vfp_nargs = 0; 1034 cif->vfp_reg_free = 0; 1035 memset (cif->vfp_args, -1, 16); /* Init to -1. */ 1036 1037 for (i = 0; i < cif->nargs; i++) 1038 { 1039 int h = vfp_type_p (cif->arg_types[i]); 1040 if (h && place_vfp_arg (cif, h) == 1) 1041 break; 1042 } 1043 }