Back to index

plt-scheme  4.2.1
ffi.c
Go to the documentation of this file.
00001 /* -----------------------------------------------------------------------
00002    ffi.c - Copyright (c) 2003, 2004, 2006, 2007 Kaz Kojima
00003    
00004    SuperH SHmedia 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 #define NGREGARG 8
00032 #define NFREGARG 12
00033 
00034 static int
00035 return_type (ffi_type *arg)
00036 {
00037 
00038   if (arg->type != FFI_TYPE_STRUCT)
00039     return arg->type;
00040 
00041   /* gcc uses r2 if the result can be packed in on register.  */
00042   if (arg->size <= sizeof (UINT8))
00043     return FFI_TYPE_UINT8;
00044   else if (arg->size <= sizeof (UINT16))
00045     return FFI_TYPE_UINT16;
00046   else if (arg->size <= sizeof (UINT32))
00047     return FFI_TYPE_UINT32;
00048   else if (arg->size <= sizeof (UINT64))
00049     return FFI_TYPE_UINT64;
00050 
00051   return FFI_TYPE_STRUCT;
00052 }
00053 
00054 /* ffi_prep_args is called by the assembly routine once stack space
00055    has been allocated for the function's arguments */
00056 
00057 void ffi_prep_args(char *stack, extended_cif *ecif)
00058 {
00059   register unsigned int i;
00060   register unsigned int avn;
00061   register void **p_argv;
00062   register char *argp;
00063   register ffi_type **p_arg;
00064 
00065   argp = stack;
00066 
00067   if (return_type (ecif->cif->rtype) == FFI_TYPE_STRUCT)
00068     {
00069       *(void **) argp = ecif->rvalue;
00070       argp += sizeof (UINT64);
00071     }
00072 
00073   avn = ecif->cif->nargs;
00074   p_argv = ecif->avalue;
00075 
00076   for (i = 0, p_arg = ecif->cif->arg_types; i < avn; i++, p_arg++, p_argv++)
00077     {
00078       size_t z;
00079       int align;
00080 
00081       z = (*p_arg)->size;
00082       align = (*p_arg)->alignment;
00083       if (z < sizeof (UINT32))
00084        {
00085          switch ((*p_arg)->type)
00086            {
00087            case FFI_TYPE_SINT8:
00088              *(SINT64 *) argp = (SINT64) *(SINT8 *)(*p_argv);
00089              break;
00090   
00091            case FFI_TYPE_UINT8:
00092              *(UINT64 *) argp = (UINT64) *(UINT8 *)(*p_argv);
00093              break;
00094   
00095            case FFI_TYPE_SINT16:
00096              *(SINT64 *) argp = (SINT64) *(SINT16 *)(*p_argv);
00097              break;
00098   
00099            case FFI_TYPE_UINT16:
00100              *(UINT64 *) argp = (UINT64) *(UINT16 *)(*p_argv);
00101              break;
00102   
00103            case FFI_TYPE_STRUCT:
00104              memcpy (argp, *p_argv, z);
00105              break;
00106 
00107            default:
00108              FFI_ASSERT(0);
00109            }
00110          argp += sizeof (UINT64);
00111        }
00112       else if (z == sizeof (UINT32) && align == sizeof (UINT32))
00113        {
00114          switch ((*p_arg)->type)
00115            {
00116            case FFI_TYPE_INT:
00117            case FFI_TYPE_SINT32:
00118              *(SINT64 *) argp = (SINT64) *(SINT32 *) (*p_argv);
00119              break;
00120 
00121            case FFI_TYPE_FLOAT:
00122            case FFI_TYPE_POINTER:
00123            case FFI_TYPE_UINT32:
00124            case FFI_TYPE_STRUCT:
00125              *(UINT64 *) argp = (UINT64) *(UINT32 *) (*p_argv);
00126              break;
00127 
00128            default:
00129              FFI_ASSERT(0);
00130              break;
00131            }
00132          argp += sizeof (UINT64);
00133        }
00134       else if (z == sizeof (UINT64)
00135               && align == sizeof (UINT64)
00136               && ((int) *p_argv & (sizeof (UINT64) - 1)) == 0)
00137        {
00138          *(UINT64 *) argp = *(UINT64 *) (*p_argv);
00139          argp += sizeof (UINT64);
00140        }
00141       else
00142        {
00143          int n = (z + sizeof (UINT64) - 1) / sizeof (UINT64);
00144 
00145          memcpy (argp, *p_argv, z);
00146          argp += n * sizeof (UINT64);
00147        }
00148     }
00149 
00150   return;
00151 }
00152 
00153 /* Perform machine dependent cif processing */
00154 ffi_status ffi_prep_cif_machdep(ffi_cif *cif)
00155 {
00156   int i, j;
00157   int size, type;
00158   int n, m;
00159   int greg;
00160   int freg;
00161   int fpair = -1;
00162 
00163   greg = (return_type (cif->rtype) == FFI_TYPE_STRUCT ? 1 : 0);
00164   freg = 0;
00165   cif->flags2 = 0;
00166 
00167   for (i = j = 0; i < cif->nargs; i++)
00168     {
00169       type = (cif->arg_types)[i]->type;
00170       switch (type)
00171        {
00172        case FFI_TYPE_FLOAT:
00173          greg++;
00174          cif->bytes += sizeof (UINT64) - sizeof (float);
00175          if (freg >= NFREGARG - 1)
00176            continue;
00177          if (fpair < 0)
00178            {
00179              fpair = freg;
00180              freg += 2;
00181            }
00182          else
00183            fpair = -1;
00184          cif->flags2 += ((cif->arg_types)[i]->type) << (2 * j++);
00185          break;
00186 
00187        case FFI_TYPE_DOUBLE:
00188          if (greg++ >= NGREGARG && (freg + 1) >= NFREGARG)
00189            continue;
00190          if ((freg + 1) < NFREGARG)
00191            {
00192              freg += 2;
00193              cif->flags2 += ((cif->arg_types)[i]->type) << (2 * j++);
00194            }
00195          else
00196            cif->flags2 += FFI_TYPE_INT << (2 * j++);
00197          break;
00198              
00199        default:
00200          size = (cif->arg_types)[i]->size;
00201          if (size < sizeof (UINT64))
00202            cif->bytes += sizeof (UINT64) - size;
00203          n = (size + sizeof (UINT64) - 1) / sizeof (UINT64);
00204          if (greg >= NGREGARG)
00205            continue;
00206          else if (greg + n - 1 >= NGREGARG)
00207            greg = NGREGARG;
00208          else
00209            greg += n;
00210          for (m = 0; m < n; m++)
00211            cif->flags2 += FFI_TYPE_INT << (2 * j++);
00212          break;
00213        }
00214     }
00215 
00216   /* Set the return type flag */
00217   switch (cif->rtype->type)
00218     {
00219     case FFI_TYPE_STRUCT:
00220       cif->flags = return_type (cif->rtype);
00221       break;
00222 
00223     case FFI_TYPE_VOID:
00224     case FFI_TYPE_FLOAT:
00225     case FFI_TYPE_DOUBLE:
00226     case FFI_TYPE_SINT64:
00227     case FFI_TYPE_UINT64:
00228       cif->flags = cif->rtype->type;
00229       break;
00230 
00231     default:
00232       cif->flags = FFI_TYPE_INT;
00233       break;
00234     }
00235 
00236   return FFI_OK;
00237 }
00238 
00239 extern void ffi_call_SYSV(void (*)(char *, extended_cif *), extended_cif *,
00240                        unsigned, unsigned, long long, unsigned *,
00241                        void (*fn)());
00242 
00243 void ffi_call(ffi_cif *cif, void (*fn)(), void *rvalue, void **avalue)
00244 {
00245   extended_cif ecif;
00246   UINT64 trvalue;
00247 
00248   ecif.cif = cif;
00249   ecif.avalue = avalue;
00250   
00251   /* If the return value is a struct and we don't have a return       */
00252   /* value address then we need to make one                     */
00253 
00254   if (cif->rtype->type == FFI_TYPE_STRUCT
00255       && return_type (cif->rtype) != FFI_TYPE_STRUCT)
00256     ecif.rvalue = &trvalue;
00257   else if ((rvalue == NULL) && 
00258       (cif->rtype->type == FFI_TYPE_STRUCT))
00259     {
00260       ecif.rvalue = alloca(cif->rtype->size);
00261     }
00262   else
00263     ecif.rvalue = rvalue;
00264 
00265   switch (cif->abi) 
00266     {
00267     case FFI_SYSV:
00268       ffi_call_SYSV(ffi_prep_args, &ecif, cif->bytes, cif->flags, cif->flags2,
00269                   ecif.rvalue, fn);
00270       break;
00271     default:
00272       FFI_ASSERT(0);
00273       break;
00274     }
00275 
00276   if (rvalue
00277       && cif->rtype->type == FFI_TYPE_STRUCT
00278       && return_type (cif->rtype) != FFI_TYPE_STRUCT)
00279     memcpy (rvalue, &trvalue, cif->rtype->size);
00280 }
00281 
00282 extern void ffi_closure_SYSV (void);
00283 extern void __ic_invalidate (void *line);
00284 
00285 ffi_status
00286 ffi_prep_closure_loc (ffi_closure *closure,
00287                     ffi_cif *cif,
00288                     void (*fun)(ffi_cif*, void*, void**, void*),
00289                     void *user_data,
00290                     void *codeloc)
00291 {
00292   unsigned int *tramp;
00293 
00294   FFI_ASSERT (cif->abi == FFI_GCC_SYSV);
00295 
00296   tramp = (unsigned int *) &closure->tramp[0];
00297   /* Since ffi_closure is an aligned object, the ffi trampoline is
00298      called as an SHcompact code.  Sigh.
00299      SHcompact part:
00300      mova @(1,pc),r0; add #1,r0; jmp @r0; nop;
00301      SHmedia part:
00302      movi fnaddr >> 16,r1; shori fnaddr,r1; ptabs/l r1,tr0
00303      movi cxt >> 16,r1; shori cxt,r1; blink tr0,r63  */
00304 #ifdef __LITTLE_ENDIAN__
00305   tramp[0] = 0x7001c701;
00306   tramp[1] = 0x0009402b;
00307 #else
00308   tramp[0] = 0xc7017001;
00309   tramp[1] = 0x402b0009;
00310 #endif
00311   tramp[2] = 0xcc000010 | (((UINT32) ffi_closure_SYSV) >> 16) << 10;
00312   tramp[3] = 0xc8000010 | (((UINT32) ffi_closure_SYSV) & 0xffff) << 10;
00313   tramp[4] = 0x6bf10600;
00314   tramp[5] = 0xcc000010 | (((UINT32) codeloc) >> 16) << 10;
00315   tramp[6] = 0xc8000010 | (((UINT32) codeloc) & 0xffff) << 10;
00316   tramp[7] = 0x4401fff0;
00317 
00318   closure->cif = cif;
00319   closure->fun = fun;
00320   closure->user_data = user_data;
00321 
00322   /* Flush the icache.  */
00323   asm volatile ("ocbwb %0,0; synco; icbi %1,0; synci" : : "r" (tramp),
00324               "r"(codeloc));
00325 
00326   return FFI_OK;
00327 }
00328 
00329 /* Basically the trampoline invokes ffi_closure_SYSV, and on 
00330  * entry, r3 holds the address of the closure.
00331  * After storing the registers that could possibly contain
00332  * parameters to be passed into the stack frame and setting
00333  * up space for a return value, ffi_closure_SYSV invokes the 
00334  * following helper function to do most of the work.
00335  */
00336 
00337 int
00338 ffi_closure_helper_SYSV (ffi_closure *closure, UINT64 *rvalue, 
00339                       UINT64 *pgr, UINT64 *pfr, UINT64 *pst)
00340 {
00341   void **avalue;
00342   ffi_type **p_arg;
00343   int i, avn;
00344   int greg, freg;
00345   ffi_cif *cif;
00346   int fpair = -1;
00347 
00348   cif = closure->cif;
00349   avalue = alloca (cif->nargs * sizeof (void *));
00350 
00351   /* Copy the caller's structure return value address so that the closure
00352      returns the data directly to the caller.  */
00353   if (return_type (cif->rtype) == FFI_TYPE_STRUCT)
00354     {
00355       rvalue = (UINT64 *) *pgr;
00356       greg = 1;
00357     }
00358   else
00359     greg = 0;
00360 
00361   freg = 0;
00362   cif = closure->cif;
00363   avn = cif->nargs;
00364 
00365   /* Grab the addresses of the arguments from the stack frame.  */
00366   for (i = 0, p_arg = cif->arg_types; i < avn; i++, p_arg++)
00367     {
00368       size_t z;
00369       void *p;
00370 
00371       z = (*p_arg)->size;
00372       if (z < sizeof (UINT32))
00373        {
00374          p = pgr + greg++;
00375 
00376          switch ((*p_arg)->type)
00377            {
00378            case FFI_TYPE_SINT8:
00379            case FFI_TYPE_UINT8:
00380            case FFI_TYPE_SINT16:
00381            case FFI_TYPE_UINT16:
00382            case FFI_TYPE_STRUCT:
00383 #ifdef __LITTLE_ENDIAN__
00384              avalue[i] = p;
00385 #else
00386              avalue[i] = ((char *) p) + sizeof (UINT32) - z;
00387 #endif
00388              break;
00389 
00390            default:
00391              FFI_ASSERT(0);
00392            }
00393        }
00394       else if (z == sizeof (UINT32))
00395        {
00396          if ((*p_arg)->type == FFI_TYPE_FLOAT)
00397            {
00398              if (freg < NFREGARG - 1)
00399               {
00400                 if (fpair >= 0)
00401                   {
00402                     avalue[i] = (UINT32 *) pfr + fpair;
00403                     fpair = -1;
00404                   }
00405                 else
00406                   {
00407 #ifdef __LITTLE_ENDIAN__
00408                     fpair = freg;
00409                     avalue[i] = (UINT32 *) pfr + (1 ^ freg);
00410 #else
00411                     fpair = 1 ^ freg;
00412                     avalue[i] = (UINT32 *) pfr + freg;
00413 #endif
00414                     freg += 2;
00415                   }
00416               }
00417              else
00418 #ifdef __LITTLE_ENDIAN__
00419               avalue[i] = pgr + greg;
00420 #else
00421               avalue[i] = (UINT32 *) (pgr + greg) + 1;
00422 #endif
00423            }
00424          else
00425 #ifdef __LITTLE_ENDIAN__
00426            avalue[i] = pgr + greg;
00427 #else
00428            avalue[i] = (UINT32 *) (pgr + greg) + 1;
00429 #endif
00430          greg++;
00431        }
00432       else if ((*p_arg)->type == FFI_TYPE_DOUBLE)
00433        {
00434          if (freg + 1 >= NFREGARG)
00435            avalue[i] = pgr + greg;
00436          else
00437            {
00438              avalue[i] = pfr + (freg >> 1);
00439              freg += 2;
00440            }
00441          greg++;
00442        }
00443       else
00444        {
00445          int n = (z + sizeof (UINT64) - 1) / sizeof (UINT64);
00446 
00447          avalue[i] = pgr + greg;
00448          greg += n;
00449        }
00450     }
00451 
00452   (closure->fun) (cif, rvalue, avalue, closure->user_data);
00453 
00454   /* Tell ffi_closure_SYSV how to perform return type promotions.  */
00455   return return_type (cif->rtype);
00456 }
00457