Back to index

plt-scheme  4.2.1
ffi.c
Go to the documentation of this file.
00001 /* -----------------------------------------------------------------------
00002    ffi.c - Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007, 2008
00003    Kaz Kojima
00004    
00005    SuperH Foreign Function Interface 
00006 
00007    Permission is hereby granted, free of charge, to any person obtaining
00008    a copy of this software and associated documentation files (the
00009    ``Software''), to deal in the Software without restriction, including
00010    without limitation the rights to use, copy, modify, merge, publish,
00011    distribute, sublicense, and/or sell copies of the Software, and to
00012    permit persons to whom the Software is furnished to do so, subject to
00013    the following conditions:
00014 
00015    The above copyright notice and this permission notice shall be included
00016    in all copies or substantial portions of the Software.
00017 
00018    THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, EXPRESS
00019    OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
00020    MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
00021    IN NO EVENT SHALL CYGNUS SOLUTIONS BE LIABLE FOR ANY CLAIM, DAMAGES OR
00022    OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
00023    ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
00024    OTHER DEALINGS IN THE SOFTWARE.
00025    ----------------------------------------------------------------------- */
00026 
00027 #include <ffi.h>
00028 #include <ffi_common.h>
00029 
00030 #include <stdlib.h>
00031 
00032 #define NGREGARG 4
00033 #if defined(__SH4__)
00034 #define NFREGARG 8
00035 #endif
00036 
00037 #if defined(__HITACHI__)
00038 #define STRUCT_VALUE_ADDRESS_WITH_ARG 1
00039 #else
00040 #define STRUCT_VALUE_ADDRESS_WITH_ARG 0
00041 #endif
00042 
00043 /* If the structure has essentialy an unique element, return its type.  */
00044 static int
00045 simple_type (ffi_type *arg)
00046 {
00047   if (arg->type != FFI_TYPE_STRUCT)
00048     return arg->type;
00049   else if (arg->elements[1])
00050     return FFI_TYPE_STRUCT;
00051 
00052   return simple_type (arg->elements[0]);
00053 }
00054 
00055 static int
00056 return_type (ffi_type *arg)
00057 {
00058   unsigned short type;
00059 
00060   if (arg->type != FFI_TYPE_STRUCT)
00061     return arg->type;
00062 
00063   type = simple_type (arg->elements[0]);
00064   if (! arg->elements[1])
00065     {
00066       switch (type)
00067        {
00068        case FFI_TYPE_SINT8:
00069        case FFI_TYPE_UINT8:
00070        case FFI_TYPE_SINT16:
00071        case FFI_TYPE_UINT16:
00072        case FFI_TYPE_SINT32:
00073        case FFI_TYPE_UINT32:
00074          return FFI_TYPE_INT;
00075 
00076        default:
00077          return type;
00078        }
00079     }
00080 
00081   /* gcc uses r0/r1 pair for some kind of structures.  */
00082   if (arg->size <= 2 * sizeof (int))
00083     {
00084       int i = 0;
00085       ffi_type *e;
00086 
00087       while ((e = arg->elements[i++]))
00088        {
00089          type = simple_type (e);
00090          switch (type)
00091            {
00092            case FFI_TYPE_SINT32:
00093            case FFI_TYPE_UINT32:
00094            case FFI_TYPE_INT:
00095            case FFI_TYPE_FLOAT:
00096              return FFI_TYPE_UINT64;
00097 
00098            default:
00099              break;
00100            }
00101        }
00102     }
00103 
00104   return FFI_TYPE_STRUCT;
00105 }
00106 
00107 /* ffi_prep_args is called by the assembly routine once stack space
00108    has been allocated for the function's arguments */
00109 
00110 void ffi_prep_args(char *stack, extended_cif *ecif)
00111 {
00112   register unsigned int i;
00113   register int tmp;
00114   register unsigned int avn;
00115   register void **p_argv;
00116   register char *argp;
00117   register ffi_type **p_arg;
00118   int greg, ireg;
00119 #if defined(__SH4__)
00120   int freg = 0;
00121 #endif
00122 
00123   tmp = 0;
00124   argp = stack;
00125 
00126   if (return_type (ecif->cif->rtype) == FFI_TYPE_STRUCT)
00127     {
00128       *(void **) argp = ecif->rvalue;
00129       argp += 4;
00130       ireg = STRUCT_VALUE_ADDRESS_WITH_ARG ? 1 : 0;
00131     }
00132   else
00133     ireg = 0;
00134 
00135   /* Set arguments for registers.  */
00136   greg = ireg;
00137   avn = ecif->cif->nargs;
00138   p_argv = ecif->avalue;
00139 
00140   for (i = 0, p_arg = ecif->cif->arg_types; i < avn; i++, p_arg++, p_argv++)
00141     {
00142       size_t z;
00143 
00144       z = (*p_arg)->size;
00145       if (z < sizeof(int))
00146        {
00147          if (greg++ >= NGREGARG)
00148            continue;
00149 
00150          z = sizeof(int);
00151          switch ((*p_arg)->type)
00152            {
00153            case FFI_TYPE_SINT8:
00154              *(signed int *) argp = (signed int)*(SINT8 *)(* p_argv);
00155              break;
00156   
00157            case FFI_TYPE_UINT8:
00158              *(unsigned int *) argp = (unsigned int)*(UINT8 *)(* p_argv);
00159              break;
00160   
00161            case FFI_TYPE_SINT16:
00162              *(signed int *) argp = (signed int)*(SINT16 *)(* p_argv);
00163              break;
00164   
00165            case FFI_TYPE_UINT16:
00166              *(unsigned int *) argp = (unsigned int)*(UINT16 *)(* p_argv);
00167              break;
00168   
00169            case FFI_TYPE_STRUCT:
00170              *(unsigned int *) argp = (unsigned int)*(UINT32 *)(* p_argv);
00171              break;
00172 
00173            default:
00174              FFI_ASSERT(0);
00175            }
00176          argp += z;
00177        }
00178       else if (z == sizeof(int))
00179        {
00180 #if defined(__SH4__)
00181          if ((*p_arg)->type == FFI_TYPE_FLOAT)
00182            {
00183              if (freg++ >= NFREGARG)
00184               continue;
00185            }
00186          else
00187 #endif
00188            {
00189              if (greg++ >= NGREGARG)
00190               continue;
00191            }
00192          *(unsigned int *) argp = (unsigned int)*(UINT32 *)(* p_argv);
00193          argp += z;
00194        }
00195 #if defined(__SH4__)
00196       else if ((*p_arg)->type == FFI_TYPE_DOUBLE)
00197        {
00198          if (freg + 1 >= NFREGARG)
00199            continue;
00200          freg = (freg + 1) & ~1;
00201          freg += 2;
00202          memcpy (argp, *p_argv, z);
00203          argp += z;
00204        }
00205 #endif
00206       else
00207        {
00208          int n = (z + sizeof (int) - 1) / sizeof (int);
00209 #if defined(__SH4__)
00210          if (greg + n - 1 >= NGREGARG)
00211            continue;
00212 #else
00213          if (greg >= NGREGARG)
00214            continue;
00215 #endif
00216          greg += n;
00217          memcpy (argp, *p_argv, z);
00218          argp += n * sizeof (int);
00219        }
00220     }
00221 
00222   /* Set arguments on stack.  */
00223   greg = ireg;
00224 #if defined(__SH4__)
00225   freg = 0;
00226 #endif
00227   p_argv = ecif->avalue;
00228 
00229   for (i = 0, p_arg = ecif->cif->arg_types; i < avn; i++, p_arg++, p_argv++)
00230     {
00231       size_t z;
00232 
00233       z = (*p_arg)->size;
00234       if (z < sizeof(int))
00235        {
00236          if (greg++ < NGREGARG)
00237            continue;
00238 
00239          z = sizeof(int);
00240          switch ((*p_arg)->type)
00241            {
00242            case FFI_TYPE_SINT8:
00243              *(signed int *) argp = (signed int)*(SINT8 *)(* p_argv);
00244              break;
00245   
00246            case FFI_TYPE_UINT8:
00247              *(unsigned int *) argp = (unsigned int)*(UINT8 *)(* p_argv);
00248              break;
00249   
00250            case FFI_TYPE_SINT16:
00251              *(signed int *) argp = (signed int)*(SINT16 *)(* p_argv);
00252              break;
00253   
00254            case FFI_TYPE_UINT16:
00255              *(unsigned int *) argp = (unsigned int)*(UINT16 *)(* p_argv);
00256              break;
00257   
00258            case FFI_TYPE_STRUCT:
00259              *(unsigned int *) argp = (unsigned int)*(UINT32 *)(* p_argv);
00260              break;
00261 
00262            default:
00263              FFI_ASSERT(0);
00264            }
00265          argp += z;
00266        }
00267       else if (z == sizeof(int))
00268        {
00269 #if defined(__SH4__)
00270          if ((*p_arg)->type == FFI_TYPE_FLOAT)
00271            {
00272              if (freg++ < NFREGARG)
00273               continue;
00274            }
00275          else
00276 #endif
00277            {
00278              if (greg++ < NGREGARG)
00279               continue;
00280            }
00281          *(unsigned int *) argp = (unsigned int)*(UINT32 *)(* p_argv);
00282          argp += z;
00283        }
00284 #if defined(__SH4__)
00285       else if ((*p_arg)->type == FFI_TYPE_DOUBLE)
00286        {
00287          if (freg + 1 < NFREGARG)
00288            {
00289              freg = (freg + 1) & ~1;
00290              freg += 2;
00291              continue;
00292            }
00293          memcpy (argp, *p_argv, z);
00294          argp += z;
00295        }
00296 #endif
00297       else
00298        {
00299          int n = (z + sizeof (int) - 1) / sizeof (int);
00300          if (greg + n - 1 < NGREGARG)
00301            {
00302              greg += n;
00303              continue;
00304            }
00305 #if (! defined(__SH4__))
00306          else if (greg < NGREGARG)
00307            {
00308              greg = NGREGARG;
00309              continue;
00310            }
00311 #endif
00312          memcpy (argp, *p_argv, z);
00313          argp += n * sizeof (int);
00314        }
00315     }
00316 
00317   return;
00318 }
00319 
00320 /* Perform machine dependent cif processing */
00321 ffi_status ffi_prep_cif_machdep(ffi_cif *cif)
00322 {
00323   int i, j;
00324   int size, type;
00325   int n, m;
00326   int greg;
00327 #if defined(__SH4__)
00328   int freg = 0;
00329 #endif
00330 
00331   cif->flags = 0;
00332 
00333   greg = ((return_type (cif->rtype) == FFI_TYPE_STRUCT) &&
00334          STRUCT_VALUE_ADDRESS_WITH_ARG) ? 1 : 0;
00335 
00336 #if defined(__SH4__)
00337   for (i = j = 0; i < cif->nargs && j < 12; i++)
00338     {
00339       type = (cif->arg_types)[i]->type;
00340       switch (type)
00341        {
00342        case FFI_TYPE_FLOAT:
00343          if (freg >= NFREGARG)
00344            continue;
00345          freg++;
00346          cif->flags += ((cif->arg_types)[i]->type) << (2 * j);
00347          j++;
00348          break;
00349 
00350        case FFI_TYPE_DOUBLE:
00351          if ((freg + 1) >= NFREGARG)
00352            continue;
00353          freg = (freg + 1) & ~1;
00354          freg += 2;
00355          cif->flags += ((cif->arg_types)[i]->type) << (2 * j);
00356          j++;
00357          break;
00358              
00359        default:
00360          size = (cif->arg_types)[i]->size;
00361          n = (size + sizeof (int) - 1) / sizeof (int);
00362          if (greg + n - 1 >= NGREGARG)
00363               continue;
00364          greg += n;
00365          for (m = 0; m < n; m++)
00366            cif->flags += FFI_TYPE_INT << (2 * j++);
00367          break;
00368        }
00369     }
00370 #else
00371   for (i = j = 0; i < cif->nargs && j < 4; i++)
00372     {
00373       size = (cif->arg_types)[i]->size;
00374       n = (size + sizeof (int) - 1) / sizeof (int);
00375       if (greg >= NGREGARG)
00376        continue;
00377       else if (greg + n - 1 >= NGREGARG)
00378        n = NGREGARG - greg;
00379       greg += n;
00380       for (m = 0; m < n; m++)
00381         cif->flags += FFI_TYPE_INT << (2 * j++);
00382     }
00383 #endif
00384 
00385   /* Set the return type flag */
00386   switch (cif->rtype->type)
00387     {
00388     case FFI_TYPE_STRUCT:
00389       cif->flags += (unsigned) (return_type (cif->rtype)) << 24;
00390       break;
00391 
00392     case FFI_TYPE_VOID:
00393     case FFI_TYPE_FLOAT:
00394     case FFI_TYPE_DOUBLE:
00395     case FFI_TYPE_SINT64:
00396     case FFI_TYPE_UINT64:
00397       cif->flags += (unsigned) cif->rtype->type << 24;
00398       break;
00399 
00400     default:
00401       cif->flags += FFI_TYPE_INT << 24;
00402       break;
00403     }
00404 
00405   return FFI_OK;
00406 }
00407 
00408 extern void ffi_call_SYSV(void (*)(char *, extended_cif *), extended_cif *,
00409                        unsigned, unsigned, unsigned *, void (*fn)());
00410 
00411 void ffi_call(ffi_cif *cif, void (*fn)(), void *rvalue, void **avalue)
00412 {
00413   extended_cif ecif;
00414   UINT64 trvalue;
00415 
00416   ecif.cif = cif;
00417   ecif.avalue = avalue;
00418   
00419   /* If the return value is a struct and we don't have a return       */
00420   /* value address then we need to make one                     */
00421 
00422   if (cif->rtype->type == FFI_TYPE_STRUCT
00423       && return_type (cif->rtype) != FFI_TYPE_STRUCT)
00424     ecif.rvalue = &trvalue;
00425   else if ((rvalue == NULL) && 
00426       (cif->rtype->type == FFI_TYPE_STRUCT))
00427     {
00428       ecif.rvalue = alloca(cif->rtype->size);
00429     }
00430   else
00431     ecif.rvalue = rvalue;
00432 
00433   switch (cif->abi) 
00434     {
00435     case FFI_SYSV:
00436       ffi_call_SYSV(ffi_prep_args, &ecif, cif->bytes, cif->flags, ecif.rvalue,
00437                   fn);
00438       break;
00439     default:
00440       FFI_ASSERT(0);
00441       break;
00442     }
00443 
00444   if (rvalue
00445       && cif->rtype->type == FFI_TYPE_STRUCT
00446       && return_type (cif->rtype) != FFI_TYPE_STRUCT)
00447     memcpy (rvalue, &trvalue, cif->rtype->size);
00448 }
00449 
00450 extern void ffi_closure_SYSV (void);
00451 #if defined(__SH4__)
00452 extern void __ic_invalidate (void *line);
00453 #endif
00454 
00455 ffi_status
00456 ffi_prep_closure_loc (ffi_closure* closure,
00457                     ffi_cif* cif,
00458                     void (*fun)(ffi_cif*, void*, void**, void*),
00459                     void *user_data,
00460                     void *codeloc)
00461 {
00462   unsigned int *tramp;
00463   unsigned int insn;
00464 
00465   FFI_ASSERT (cif->abi == FFI_GCC_SYSV);
00466 
00467   tramp = (unsigned int *) &closure->tramp[0];
00468   /* Set T bit if the function returns a struct pointed with R2.  */
00469   insn = (return_type (cif->rtype) == FFI_TYPE_STRUCT
00470          ? 0x0018 /* sett */
00471          : 0x0008 /* clrt */);
00472 
00473 #ifdef __LITTLE_ENDIAN__
00474   tramp[0] = 0xd301d102;
00475   tramp[1] = 0x0000412b | (insn << 16);
00476 #else
00477   tramp[0] = 0xd102d301;
00478   tramp[1] = 0x412b0000 | insn;
00479 #endif
00480   *(void **) &tramp[2] = (void *)codeloc;          /* ctx */
00481   *(void **) &tramp[3] = (void *)ffi_closure_SYSV; /* funaddr */
00482 
00483   closure->cif = cif;
00484   closure->fun = fun;
00485   closure->user_data = user_data;
00486 
00487 #if defined(__SH4__)
00488   /* Flush the icache.  */
00489   __ic_invalidate(codeloc);
00490 #endif
00491 
00492   return FFI_OK;
00493 }
00494 
00495 /* Basically the trampoline invokes ffi_closure_SYSV, and on 
00496  * entry, r3 holds the address of the closure.
00497  * After storing the registers that could possibly contain
00498  * parameters to be passed into the stack frame and setting
00499  * up space for a return value, ffi_closure_SYSV invokes the 
00500  * following helper function to do most of the work.
00501  */
00502 
00503 #ifdef __LITTLE_ENDIAN__
00504 #define OFS_INT8     0
00505 #define OFS_INT16    0
00506 #else
00507 #define OFS_INT8     3
00508 #define OFS_INT16    2
00509 #endif
00510 
00511 int
00512 ffi_closure_helper_SYSV (ffi_closure *closure, void *rvalue, 
00513                       unsigned long *pgr, unsigned long *pfr, 
00514                       unsigned long *pst)
00515 {
00516   void **avalue;
00517   ffi_type **p_arg;
00518   int i, avn;
00519   int ireg, greg = 0;
00520 #if defined(__SH4__)
00521   int freg = 0;
00522 #endif
00523   ffi_cif *cif; 
00524 
00525   cif = closure->cif;
00526   avalue = alloca(cif->nargs * sizeof(void *));
00527 
00528   /* Copy the caller's structure return value address so that the closure
00529      returns the data directly to the caller.  */
00530   if (cif->rtype->type == FFI_TYPE_STRUCT && STRUCT_VALUE_ADDRESS_WITH_ARG)
00531     {
00532       rvalue = (void *) *pgr++;
00533       ireg = 1;
00534     }
00535   else
00536     ireg = 0;
00537 
00538   cif = closure->cif;
00539   greg = ireg;
00540   avn = cif->nargs;
00541 
00542   /* Grab the addresses of the arguments from the stack frame.  */
00543   for (i = 0, p_arg = cif->arg_types; i < avn; i++, p_arg++)
00544     {
00545       size_t z;
00546 
00547       z = (*p_arg)->size;
00548       if (z < sizeof(int))
00549        {
00550          if (greg++ >= NGREGARG)
00551            continue;
00552 
00553          z = sizeof(int);
00554          switch ((*p_arg)->type)
00555            {
00556            case FFI_TYPE_SINT8:
00557            case FFI_TYPE_UINT8:
00558              avalue[i] = (((char *)pgr) + OFS_INT8);
00559              break;
00560   
00561            case FFI_TYPE_SINT16:
00562            case FFI_TYPE_UINT16:
00563              avalue[i] = (((char *)pgr) + OFS_INT16);
00564              break;
00565   
00566            case FFI_TYPE_STRUCT:
00567              avalue[i] = pgr;
00568              break;
00569 
00570            default:
00571              FFI_ASSERT(0);
00572            }
00573          pgr++;
00574        }
00575       else if (z == sizeof(int))
00576        {
00577 #if defined(__SH4__)
00578          if ((*p_arg)->type == FFI_TYPE_FLOAT)
00579            {
00580              if (freg++ >= NFREGARG)
00581               continue;
00582              avalue[i] = pfr;
00583              pfr++;
00584            }
00585          else
00586 #endif
00587            {
00588              if (greg++ >= NGREGARG)
00589               continue;
00590              avalue[i] = pgr;
00591              pgr++;
00592            }
00593        }
00594 #if defined(__SH4__)
00595       else if ((*p_arg)->type == FFI_TYPE_DOUBLE)
00596        {
00597          if (freg + 1 >= NFREGARG)
00598            continue;
00599          if (freg & 1)
00600            pfr++;
00601          freg = (freg + 1) & ~1;
00602          freg += 2;
00603          avalue[i] = pfr;
00604          pfr += 2;
00605        }
00606 #endif
00607       else
00608        {
00609          int n = (z + sizeof (int) - 1) / sizeof (int);
00610 #if defined(__SH4__)
00611          if (greg + n - 1 >= NGREGARG)
00612            continue;
00613 #else
00614          if (greg >= NGREGARG)
00615            continue;
00616 #endif
00617          greg += n;
00618          avalue[i] = pgr;
00619          pgr += n;
00620        }
00621     }
00622 
00623   greg = ireg;
00624 #if defined(__SH4__)
00625   freg = 0;
00626 #endif
00627 
00628   for (i = 0, p_arg = cif->arg_types; i < avn; i++, p_arg++)
00629     {
00630       size_t z;
00631 
00632       z = (*p_arg)->size;
00633       if (z < sizeof(int))
00634        {
00635          if (greg++ < NGREGARG)
00636            continue;
00637 
00638          z = sizeof(int);
00639          switch ((*p_arg)->type)
00640            {
00641            case FFI_TYPE_SINT8:
00642            case FFI_TYPE_UINT8:
00643              avalue[i] = (((char *)pst) + OFS_INT8);
00644              break;
00645   
00646            case FFI_TYPE_SINT16:
00647            case FFI_TYPE_UINT16:
00648              avalue[i] = (((char *)pst) + OFS_INT16);
00649              break;
00650   
00651            case FFI_TYPE_STRUCT:
00652              avalue[i] = pst;
00653              break;
00654 
00655            default:
00656              FFI_ASSERT(0);
00657            }
00658          pst++;
00659        }
00660       else if (z == sizeof(int))
00661        {
00662 #if defined(__SH4__)
00663          if ((*p_arg)->type == FFI_TYPE_FLOAT)
00664            {
00665              if (freg++ < NFREGARG)
00666               continue;
00667            }
00668          else
00669 #endif
00670            {
00671              if (greg++ < NGREGARG)
00672               continue;
00673            }
00674          avalue[i] = pst;
00675          pst++;
00676        }
00677 #if defined(__SH4__)
00678       else if ((*p_arg)->type == FFI_TYPE_DOUBLE)
00679        {
00680          if (freg + 1 < NFREGARG)
00681            {
00682              freg = (freg + 1) & ~1;
00683              freg += 2;
00684              continue;
00685            }
00686          avalue[i] = pst;
00687          pst += 2;
00688        }
00689 #endif
00690       else
00691        {
00692          int n = (z + sizeof (int) - 1) / sizeof (int);
00693          if (greg + n - 1 < NGREGARG)
00694            {
00695              greg += n;
00696              continue;
00697            }
00698 #if (! defined(__SH4__))
00699          else if (greg < NGREGARG)
00700            {
00701              greg += n;
00702              pst += greg - NGREGARG;
00703              continue;
00704            }
00705 #endif
00706          avalue[i] = pst;
00707          pst += n;
00708        }
00709     }
00710 
00711   (closure->fun) (cif, rvalue, avalue, closure->user_data);
00712 
00713   /* Tell ffi_closure_SYSV how to perform return type promotions.  */
00714   return return_type (cif->rtype);
00715 }