Back to index

plt-scheme  4.2.1
ffi.c
Go to the documentation of this file.
00001 /* -----------------------------------------------------------------------
00002    ffi.c - Copyright (c) 1996, 2003, 2004, 2007 Red Hat, Inc.
00003    
00004    SPARC Foreign Function Interface 
00005 
00006    Permission is hereby granted, free of charge, to any person obtaining
00007    a copy of this software and associated documentation files (the
00008    ``Software''), to deal in the Software without restriction, including
00009    without limitation the rights to use, copy, modify, merge, publish,
00010    distribute, sublicense, and/or sell copies of the Software, and to
00011    permit persons to whom the Software is furnished to do so, subject to
00012    the following conditions:
00013 
00014    The above copyright notice and this permission notice shall be included
00015    in all copies or substantial portions of the Software.
00016 
00017    THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, EXPRESS
00018    OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
00019    MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
00020    IN NO EVENT SHALL CYGNUS SOLUTIONS BE LIABLE FOR ANY CLAIM, DAMAGES OR
00021    OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
00022    ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
00023    OTHER DEALINGS IN THE SOFTWARE.
00024    ----------------------------------------------------------------------- */
00025 
00026 #include <ffi.h>
00027 #include <ffi_common.h>
00028 
00029 #include <stdlib.h>
00030 
00031 
00032 /* ffi_prep_args is called by the assembly routine once stack space
00033    has been allocated for the function's arguments */
00034 
00035 void ffi_prep_args_v8(char *stack, extended_cif *ecif)
00036 {
00037   int i;
00038   void **p_argv;
00039   char *argp;
00040   ffi_type **p_arg;
00041 
00042   /* Skip 16 words for the window save area */
00043   argp = stack + 16*sizeof(int);
00044 
00045   /* This should only really be done when we are returning a structure,
00046      however, it's faster just to do it all the time...
00047 
00048   if ( ecif->cif->rtype->type == FFI_TYPE_STRUCT ) */
00049   *(int *) argp = (long)ecif->rvalue;
00050 
00051   /* And 1 word for the  structure return value. */
00052   argp += sizeof(int);
00053 
00054 #ifdef USING_PURIFY
00055   /* Purify will probably complain in our assembly routine, unless we
00056      zero out this memory. */
00057 
00058   ((int*)argp)[0] = 0;
00059   ((int*)argp)[1] = 0;
00060   ((int*)argp)[2] = 0;
00061   ((int*)argp)[3] = 0;
00062   ((int*)argp)[4] = 0;
00063   ((int*)argp)[5] = 0;
00064 #endif
00065 
00066   p_argv = ecif->avalue;
00067 
00068   for (i = ecif->cif->nargs, p_arg = ecif->cif->arg_types; i; i--, p_arg++)
00069     {
00070       size_t z;
00071 
00072          if ((*p_arg)->type == FFI_TYPE_STRUCT
00073 #if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
00074              || (*p_arg)->type == FFI_TYPE_LONGDOUBLE
00075 #endif
00076              )
00077            {
00078              *(unsigned int *) argp = (unsigned long)(* p_argv);
00079              z = sizeof(int);
00080            }
00081          else
00082            {
00083              z = (*p_arg)->size;
00084              if (z < sizeof(int))
00085               {
00086                 z = sizeof(int);
00087                 switch ((*p_arg)->type)
00088                   {
00089                   case FFI_TYPE_SINT8:
00090                     *(signed int *) argp = *(SINT8 *)(* p_argv);
00091                     break;
00092                     
00093                   case FFI_TYPE_UINT8:
00094                     *(unsigned int *) argp = *(UINT8 *)(* p_argv);
00095                     break;
00096                     
00097                   case FFI_TYPE_SINT16:
00098                     *(signed int *) argp = *(SINT16 *)(* p_argv);
00099                     break;
00100                     
00101                   case FFI_TYPE_UINT16:
00102                     *(unsigned int *) argp = *(UINT16 *)(* p_argv);
00103                     break;
00104 
00105                   default:
00106                     FFI_ASSERT(0);
00107                   }
00108               }
00109              else
00110               {
00111                 memcpy(argp, *p_argv, z);
00112               }
00113            }
00114          p_argv++;
00115          argp += z;
00116     }
00117   
00118   return;
00119 }
00120 
00121 int ffi_prep_args_v9(char *stack, extended_cif *ecif)
00122 {
00123   int i, ret = 0;
00124   int tmp;
00125   void **p_argv;
00126   char *argp;
00127   ffi_type **p_arg;
00128 
00129   tmp = 0;
00130 
00131   /* Skip 16 words for the window save area */
00132   argp = stack + 16*sizeof(long long);
00133 
00134 #ifdef USING_PURIFY
00135   /* Purify will probably complain in our assembly routine, unless we
00136      zero out this memory. */
00137 
00138   ((long long*)argp)[0] = 0;
00139   ((long long*)argp)[1] = 0;
00140   ((long long*)argp)[2] = 0;
00141   ((long long*)argp)[3] = 0;
00142   ((long long*)argp)[4] = 0;
00143   ((long long*)argp)[5] = 0;
00144 #endif
00145 
00146   p_argv = ecif->avalue;
00147 
00148   if (ecif->cif->rtype->type == FFI_TYPE_STRUCT &&
00149       ecif->cif->rtype->size > 32)
00150     {
00151       *(unsigned long long *) argp = (unsigned long)ecif->rvalue;
00152       argp += sizeof(long long);
00153       tmp = 1;
00154     }
00155 
00156   for (i = 0, p_arg = ecif->cif->arg_types; i < ecif->cif->nargs;
00157        i++, p_arg++)
00158     {
00159       size_t z;
00160 
00161       z = (*p_arg)->size;
00162       switch ((*p_arg)->type)
00163        {
00164        case FFI_TYPE_STRUCT:
00165          if (z > 16)
00166            {
00167              /* For structures larger than 16 bytes we pass reference.  */
00168              *(unsigned long long *) argp = (unsigned long)* p_argv;
00169              argp += sizeof(long long);
00170              tmp++;
00171              p_argv++;
00172              continue;
00173            }
00174          /* FALLTHROUGH */
00175        case FFI_TYPE_FLOAT:
00176        case FFI_TYPE_DOUBLE:
00177 #if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
00178        case FFI_TYPE_LONGDOUBLE:
00179 #endif
00180          ret = 1; /* We should promote into FP regs as well as integer.  */
00181          break;
00182        }
00183       if (z < sizeof(long long))
00184        {
00185          switch ((*p_arg)->type)
00186            {
00187            case FFI_TYPE_SINT8:
00188              *(signed long long *) argp = *(SINT8 *)(* p_argv);
00189              break;
00190 
00191            case FFI_TYPE_UINT8:
00192              *(unsigned long long *) argp = *(UINT8 *)(* p_argv);
00193              break;
00194 
00195            case FFI_TYPE_SINT16:
00196              *(signed long long *) argp = *(SINT16 *)(* p_argv);
00197              break;
00198 
00199            case FFI_TYPE_UINT16:
00200              *(unsigned long long *) argp = *(UINT16 *)(* p_argv);
00201              break;
00202 
00203            case FFI_TYPE_SINT32:
00204              *(signed long long *) argp = *(SINT32 *)(* p_argv);
00205              break;
00206 
00207            case FFI_TYPE_UINT32:
00208              *(unsigned long long *) argp = *(UINT32 *)(* p_argv);
00209              break;
00210 
00211            case FFI_TYPE_FLOAT:
00212              *(float *) (argp + 4) = *(FLOAT32 *)(* p_argv); /* Right justify */
00213              break;
00214 
00215            case FFI_TYPE_STRUCT:
00216              memcpy(argp, *p_argv, z);
00217              break;
00218 
00219            default:
00220              FFI_ASSERT(0);
00221            }
00222          z = sizeof(long long);
00223          tmp++;
00224        }
00225       else if (z == sizeof(long long))
00226        {
00227          memcpy(argp, *p_argv, z);
00228          z = sizeof(long long);
00229          tmp++;
00230        }
00231       else
00232        {
00233          if ((tmp & 1) && (*p_arg)->alignment > 8)
00234            {
00235              tmp++;
00236              argp += sizeof(long long);
00237            }
00238          memcpy(argp, *p_argv, z);
00239          z = 2 * sizeof(long long);
00240          tmp += 2;
00241        }
00242       p_argv++;
00243       argp += z;
00244     }
00245 
00246   return ret;
00247 }
00248 
00249 /* Perform machine dependent cif processing */
00250 ffi_status ffi_prep_cif_machdep(ffi_cif *cif)
00251 {
00252   int wordsize;
00253 
00254   if (cif->abi != FFI_V9)
00255     {
00256       wordsize = 4;
00257 
00258       /* If we are returning a struct, this will already have been added.
00259         Otherwise we need to add it because it's always got to be there! */
00260 
00261       if (cif->rtype->type != FFI_TYPE_STRUCT)
00262        cif->bytes += wordsize;
00263 
00264       /* sparc call frames require that space is allocated for 6 args,
00265         even if they aren't used. Make that space if necessary. */
00266   
00267       if (cif->bytes < 4*6+4)
00268        cif->bytes = 4*6+4;
00269     }
00270   else
00271     {
00272       wordsize = 8;
00273 
00274       /* sparc call frames require that space is allocated for 6 args,
00275         even if they aren't used. Make that space if necessary. */
00276   
00277       if (cif->bytes < 8*6)
00278        cif->bytes = 8*6;
00279     }
00280 
00281   /* Adjust cif->bytes. to include 16 words for the window save area,
00282      and maybe the struct/union return pointer area, */
00283 
00284   cif->bytes += 16 * wordsize;
00285 
00286   /* The stack must be 2 word aligned, so round bytes up
00287      appropriately. */
00288 
00289   cif->bytes = ALIGN(cif->bytes, 2 * wordsize);
00290 
00291   /* Set the return type flag */
00292   switch (cif->rtype->type)
00293     {
00294     case FFI_TYPE_VOID:
00295     case FFI_TYPE_FLOAT:
00296     case FFI_TYPE_DOUBLE:
00297 #if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
00298     case FFI_TYPE_LONGDOUBLE:
00299 #endif
00300       cif->flags = cif->rtype->type;
00301       break;
00302 
00303     case FFI_TYPE_STRUCT:
00304       if (cif->abi == FFI_V9 && cif->rtype->size > 32)
00305        cif->flags = FFI_TYPE_VOID;
00306       else
00307        cif->flags = FFI_TYPE_STRUCT;
00308       break;
00309 
00310     case FFI_TYPE_SINT64:
00311     case FFI_TYPE_UINT64:
00312       if (cif->abi != FFI_V9)
00313        {
00314          cif->flags = FFI_TYPE_SINT64;
00315          break;
00316        }
00317       /* FALLTHROUGH */
00318     default:
00319       cif->flags = FFI_TYPE_INT;
00320       break;
00321     }
00322   return FFI_OK;
00323 }
00324 
00325 int ffi_v9_layout_struct(ffi_type *arg, int off, char *ret, char *intg, char *flt)
00326 {
00327   ffi_type **ptr = &arg->elements[0];
00328 
00329   while (*ptr != NULL)
00330     {
00331       if (off & ((*ptr)->alignment - 1))
00332        off = ALIGN(off, (*ptr)->alignment);
00333 
00334       switch ((*ptr)->type)
00335        {
00336        case FFI_TYPE_STRUCT:
00337          off = ffi_v9_layout_struct(*ptr, off, ret, intg, flt);
00338          off = ALIGN(off, FFI_SIZEOF_ARG);
00339          break;
00340        case FFI_TYPE_FLOAT:
00341        case FFI_TYPE_DOUBLE:
00342 #if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
00343        case FFI_TYPE_LONGDOUBLE:
00344 #endif
00345          memmove(ret + off, flt + off, (*ptr)->size);
00346          off += (*ptr)->size;
00347          break;
00348        default:
00349          memmove(ret + off, intg + off, (*ptr)->size);
00350          off += (*ptr)->size;
00351          break;
00352        }
00353       ptr++;
00354     }
00355   return off;
00356 }
00357 
00358 
00359 #ifdef SPARC64
00360 extern int ffi_call_v9(void *, extended_cif *, unsigned, 
00361                      unsigned, unsigned *, void (*fn)());
00362 #else
00363 extern int ffi_call_v8(void *, extended_cif *, unsigned, 
00364                      unsigned, unsigned *, void (*fn)());
00365 #endif
00366 
00367 void ffi_call(ffi_cif *cif, void (*fn)(), void *rvalue, void **avalue)
00368 {
00369   extended_cif ecif;
00370   void *rval = rvalue;
00371 
00372   ecif.cif = cif;
00373   ecif.avalue = avalue;
00374 
00375   /* If the return value is a struct and we don't have a return       */
00376   /* value address then we need to make one                     */
00377 
00378   ecif.rvalue = rvalue;
00379   if (cif->rtype->type == FFI_TYPE_STRUCT)
00380     {
00381       if (cif->rtype->size <= 32)
00382        rval = alloca(64);
00383       else
00384        {
00385          rval = NULL;
00386          if (rvalue == NULL)
00387            ecif.rvalue = alloca(cif->rtype->size);
00388        }
00389     }
00390 
00391   switch (cif->abi) 
00392     {
00393     case FFI_V8:
00394 #ifdef SPARC64
00395       /* We don't yet support calling 32bit code from 64bit */
00396       FFI_ASSERT(0);
00397 #else
00398       ffi_call_v8(ffi_prep_args_v8, &ecif, cif->bytes, 
00399                 cif->flags, rvalue, fn);
00400 #endif
00401       break;
00402     case FFI_V9:
00403 #ifdef SPARC64
00404       ffi_call_v9(ffi_prep_args_v9, &ecif, cif->bytes,
00405                 cif->flags, rval, fn);
00406       if (rvalue && rval && cif->rtype->type == FFI_TYPE_STRUCT)
00407        ffi_v9_layout_struct(cif->rtype, 0, (char *)rvalue, (char *)rval, ((char *)rval)+32);
00408 #else
00409       /* And vice versa */
00410       FFI_ASSERT(0);
00411 #endif
00412       break;
00413     default:
00414       FFI_ASSERT(0);
00415       break;
00416     }
00417 
00418 }
00419 
00420 
00421 #ifdef SPARC64
00422 extern void ffi_closure_v9(void);
00423 #else
00424 extern void ffi_closure_v8(void);
00425 #endif
00426 
00427 ffi_status
00428 ffi_prep_closure_loc (ffi_closure* closure,
00429                     ffi_cif* cif,
00430                     void (*fun)(ffi_cif*, void*, void**, void*),
00431                     void *user_data,
00432                     void *codeloc)
00433 {
00434   unsigned int *tramp = (unsigned int *) &closure->tramp[0];
00435   unsigned long fn;
00436 #ifdef SPARC64
00437   /* Trampoline address is equal to the closure address.  We take advantage
00438      of that to reduce the trampoline size by 8 bytes. */
00439   FFI_ASSERT (cif->abi == FFI_V9);
00440   fn = (unsigned long) ffi_closure_v9;
00441   tramp[0] = 0x83414000;    /* rd  %pc, %g1      */
00442   tramp[1] = 0xca586010;    /* ldx [%g1+16], %g5 */
00443   tramp[2] = 0x81c14000;    /* jmp %g5           */
00444   tramp[3] = 0x01000000;    /* nop               */
00445   *((unsigned long *) &tramp[4]) = fn;
00446 #else
00447   unsigned long ctx = (unsigned long) codeloc;
00448   FFI_ASSERT (cif->abi == FFI_V8);
00449   fn = (unsigned long) ffi_closure_v8;
00450   tramp[0] = 0x03000000 | fn >> 10;       /* sethi %hi(fn), %g1       */
00451   tramp[1] = 0x05000000 | ctx >> 10;      /* sethi %hi(ctx), %g2      */
00452   tramp[2] = 0x81c06000 | (fn & 0x3ff);   /* jmp   %g1+%lo(fn) */
00453   tramp[3] = 0x8410a000 | (ctx & 0x3ff);/* or    %g2, %lo(ctx) */
00454 #endif
00455 
00456   closure->cif = cif;
00457   closure->fun = fun;
00458   closure->user_data = user_data;
00459 
00460   /* Flush the Icache.  FIXME: alignment isn't certain, assume 8 bytes */
00461 #ifdef SPARC64
00462   asm volatile ("flush      %0" : : "r" (closure) : "memory");
00463   asm volatile ("flush      %0" : : "r" (((char *) closure) + 8) : "memory");
00464 #else
00465   asm volatile ("iflush     %0" : : "r" (closure) : "memory");
00466   asm volatile ("iflush     %0" : : "r" (((char *) closure) + 8) : "memory");
00467 #endif
00468 
00469   return FFI_OK;
00470 }
00471 
00472 int
00473 ffi_closure_sparc_inner_v8(ffi_closure *closure,
00474   void *rvalue, unsigned long *gpr, unsigned long *scratch)
00475 {
00476   ffi_cif *cif;
00477   ffi_type **arg_types;
00478   void **avalue;
00479   int i, argn;
00480 
00481   cif = closure->cif;
00482   arg_types = cif->arg_types;
00483   avalue = alloca(cif->nargs * sizeof(void *));
00484 
00485   /* Copy the caller's structure return address so that the closure
00486      returns the data directly to the caller.  */
00487   if (cif->flags == FFI_TYPE_STRUCT
00488 #if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE  
00489       || cif->flags == FFI_TYPE_LONGDOUBLE
00490 #endif
00491      )
00492     rvalue = (void *) gpr[0];
00493 
00494   /* Always skip the structure return address.  */
00495   argn = 1;
00496 
00497   /* Grab the addresses of the arguments from the stack frame.  */
00498   for (i = 0; i < cif->nargs; i++)
00499     {
00500       if (arg_types[i]->type == FFI_TYPE_STRUCT
00501 #if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
00502          || arg_types[i]->type == FFI_TYPE_LONGDOUBLE
00503 #endif
00504          )
00505        {
00506          /* Straight copy of invisible reference.  */
00507          avalue[i] = (void *)gpr[argn++];
00508        }
00509       else if ((arg_types[i]->type == FFI_TYPE_DOUBLE
00510               || arg_types[i]->type == FFI_TYPE_SINT64
00511               || arg_types[i]->type == FFI_TYPE_UINT64)
00512               /* gpr is 8-byte aligned.  */
00513               && (argn % 2) != 0)
00514        {
00515          /* Align on a 8-byte boundary.  */
00516          scratch[0] = gpr[argn];
00517          scratch[1] = gpr[argn+1];
00518          avalue[i] = scratch;
00519          scratch -= 2;
00520          argn += 2;
00521        }
00522       else
00523        {
00524          /* Always right-justify.  */
00525          argn += ALIGN(arg_types[i]->size, FFI_SIZEOF_ARG) / FFI_SIZEOF_ARG;
00526          avalue[i] = ((char *) &gpr[argn]) - arg_types[i]->size;
00527        }
00528     }
00529 
00530   /* Invoke the closure.  */
00531   (closure->fun) (cif, rvalue, avalue, closure->user_data);
00532 
00533   /* Tell ffi_closure_sparc how to perform return type promotions.  */
00534   return cif->rtype->type;
00535 }
00536 
00537 int
00538 ffi_closure_sparc_inner_v9(ffi_closure *closure,
00539   void *rvalue, unsigned long *gpr, double *fpr)
00540 {
00541   ffi_cif *cif;
00542   ffi_type **arg_types;
00543   void **avalue;
00544   int i, argn, fp_slot_max;
00545 
00546   cif = closure->cif;
00547   arg_types = cif->arg_types;
00548   avalue = alloca(cif->nargs * sizeof(void *));
00549 
00550   /* Copy the caller's structure return address so that the closure
00551      returns the data directly to the caller.  */
00552   if (cif->flags == FFI_TYPE_VOID
00553       && cif->rtype->type == FFI_TYPE_STRUCT)
00554     {
00555       rvalue = (void *) gpr[0];
00556       /* Skip the structure return address.  */
00557       argn = 1;
00558     }
00559   else
00560     argn = 0;
00561 
00562   fp_slot_max = 16 - argn;
00563 
00564   /* Grab the addresses of the arguments from the stack frame.  */
00565   for (i = 0; i < cif->nargs; i++)
00566     {
00567       if (arg_types[i]->type == FFI_TYPE_STRUCT)
00568        {
00569          if (arg_types[i]->size > 16)
00570            {
00571              /* Straight copy of invisible reference.  */
00572              avalue[i] = (void *)gpr[argn++];
00573            }
00574          else
00575            {
00576              /* Left-justify.  */
00577              ffi_v9_layout_struct(arg_types[i],
00578                                0,
00579                                (char *) &gpr[argn],
00580                                (char *) &gpr[argn],
00581                                (char *) &fpr[argn]);
00582              avalue[i] = &gpr[argn];
00583              argn += ALIGN(arg_types[i]->size, FFI_SIZEOF_ARG) / FFI_SIZEOF_ARG;
00584            }
00585        }
00586       else
00587        {
00588          /* Right-justify.  */
00589          argn += ALIGN(arg_types[i]->size, FFI_SIZEOF_ARG) / FFI_SIZEOF_ARG;
00590 
00591          if (i < fp_slot_max
00592              && (arg_types[i]->type == FFI_TYPE_FLOAT
00593                 || arg_types[i]->type == FFI_TYPE_DOUBLE
00594 #if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
00595                 || arg_types[i]->type == FFI_TYPE_LONGDOUBLE
00596 #endif
00597                 ))
00598            avalue[i] = ((char *) &fpr[argn]) - arg_types[i]->size;
00599          else
00600            avalue[i] = ((char *) &gpr[argn]) - arg_types[i]->size;
00601        }
00602     }
00603 
00604   /* Invoke the closure.  */
00605   (closure->fun) (cif, rvalue, avalue, closure->user_data);
00606 
00607   /* Tell ffi_closure_sparc how to perform return type promotions.  */
00608   return cif->rtype->type;
00609 }