Back to index

plt-scheme  4.2.1
ffi.c
Go to the documentation of this file.
00001 /* -----------------------------------------------------------------------
00002    ffi.c - Copyright (c) 2004  Anthony Green
00003    Copyright (C) 2007  Free Software Foundation, Inc.
00004    
00005    FR-V 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 /* 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(char *stack, extended_cif *ecif)
00036 {
00037   register unsigned int i;
00038   register void **p_argv;
00039   register char *argp;
00040   register ffi_type **p_arg;
00041   register int count = 0;
00042 
00043   p_argv = ecif->avalue;
00044   argp = stack;
00045 
00046   for (i = ecif->cif->nargs, p_arg = ecif->cif->arg_types;
00047        (i != 0);
00048        i--, p_arg++)
00049     {
00050       size_t z;
00051       
00052       z = (*p_arg)->size;
00053 
00054       if ((*p_arg)->type == FFI_TYPE_STRUCT)
00055        {
00056          z = sizeof(void*);
00057          *(void **) argp = *p_argv;
00058        } 
00059       /*      if ((*p_arg)->type == FFI_TYPE_FLOAT)
00060        {
00061          if (count > 24)
00062            {
00063              // This is going on the stack.  Turn it into a double.  
00064              *(double *) argp = (double) *(float*)(* p_argv);
00065              z = sizeof(double);
00066            }
00067          else
00068            *(void **) argp = *(void **)(* p_argv);
00069        }  */
00070       else if (z < sizeof(int))
00071        {
00072          z = sizeof(int);
00073          switch ((*p_arg)->type)
00074            {
00075            case FFI_TYPE_SINT8:
00076              *(signed int *) argp = (signed int)*(SINT8 *)(* p_argv);
00077              break;
00078              
00079            case FFI_TYPE_UINT8:
00080              *(unsigned int *) argp = (unsigned int)*(UINT8 *)(* p_argv);
00081              break;
00082              
00083            case FFI_TYPE_SINT16:
00084              *(signed int *) argp = (signed int)*(SINT16 *)(* p_argv);
00085              break;
00086                 
00087            case FFI_TYPE_UINT16:
00088              *(unsigned int *) argp = (unsigned int)*(UINT16 *)(* p_argv);
00089              break;
00090                 
00091            default:
00092              FFI_ASSERT(0);
00093            }
00094        }
00095       else if (z == sizeof(int))
00096        {
00097          *(unsigned int *) argp = (unsigned int)*(UINT32 *)(* p_argv);
00098        }
00099       else
00100        {
00101          memcpy(argp, *p_argv, z);
00102        }
00103       p_argv++;
00104       argp += z;
00105       count += z;
00106     }
00107 
00108   return (stack + ((count > 24) ? 24 : ALIGN_DOWN(count, 8)));
00109 }
00110 
00111 /* Perform machine dependent cif processing */
00112 ffi_status ffi_prep_cif_machdep(ffi_cif *cif)
00113 {
00114   if (cif->rtype->type == FFI_TYPE_STRUCT)
00115     cif->flags = -1;
00116   else
00117     cif->flags = cif->rtype->size;
00118 
00119   cif->bytes = ALIGN (cif->bytes, 8);
00120 
00121   return FFI_OK;
00122 }
00123 
00124 extern void ffi_call_EABI(void *(*)(char *, extended_cif *), 
00125                        extended_cif *, 
00126                        unsigned, unsigned, 
00127                        unsigned *, 
00128                        void (*fn)());
00129 
00130 void ffi_call(ffi_cif *cif, 
00131              void (*fn)(), 
00132              void *rvalue, 
00133              void **avalue)
00134 {
00135   extended_cif ecif;
00136 
00137   ecif.cif = cif;
00138   ecif.avalue = avalue;
00139   
00140   /* If the return value is a struct and we don't have a return       */
00141   /* value address then we need to make one                     */
00142 
00143   if ((rvalue == NULL) && 
00144       (cif->rtype->type == FFI_TYPE_STRUCT))
00145     {
00146       ecif.rvalue = alloca(cif->rtype->size);
00147     }
00148   else
00149     ecif.rvalue = rvalue;
00150     
00151   
00152   switch (cif->abi) 
00153     {
00154     case FFI_EABI:
00155       ffi_call_EABI(ffi_prep_args, &ecif, cif->bytes, 
00156                   cif->flags, ecif.rvalue, fn);
00157       break;
00158     default:
00159       FFI_ASSERT(0);
00160       break;
00161     }
00162 }
00163 
00164 void ffi_closure_eabi (unsigned arg1, unsigned arg2, unsigned arg3,
00165                      unsigned arg4, unsigned arg5, unsigned arg6)
00166 {
00167   /* This function is called by a trampoline.  The trampoline stows a
00168      pointer to the ffi_closure object in gr7.  We must save this
00169      pointer in a place that will persist while we do our work.  */
00170   register ffi_closure *creg __asm__ ("gr7");
00171   ffi_closure *closure = creg;
00172 
00173   /* Arguments that don't fit in registers are found on the stack
00174      at a fixed offset above the current frame pointer.  */
00175   register char *frame_pointer __asm__ ("fp");
00176   char *stack_args = frame_pointer + 16;
00177 
00178   /* Lay the register arguments down in a continuous chunk of memory.  */
00179   unsigned register_args[6] =
00180     { arg1, arg2, arg3, arg4, arg5, arg6 };
00181 
00182   ffi_cif *cif = closure->cif;
00183   ffi_type **arg_types = cif->arg_types;
00184   void **avalue = alloca (cif->nargs * sizeof(void *));
00185   char *ptr = (char *) register_args;
00186   int i;
00187 
00188   /* Find the address of each argument.  */
00189   for (i = 0; i < cif->nargs; i++)
00190     {
00191       switch (arg_types[i]->type)
00192        {
00193        case FFI_TYPE_SINT8:
00194        case FFI_TYPE_UINT8:
00195          avalue[i] = ptr + 3;
00196          break;
00197        case FFI_TYPE_SINT16:
00198        case FFI_TYPE_UINT16:
00199          avalue[i] = ptr + 2;
00200          break;
00201        case FFI_TYPE_SINT32:
00202        case FFI_TYPE_UINT32:
00203        case FFI_TYPE_FLOAT:
00204          avalue[i] = ptr;
00205          break;
00206        case FFI_TYPE_STRUCT:
00207          avalue[i] = *(void**)ptr;
00208          break;
00209        default:
00210          /* This is an 8-byte value.  */
00211          avalue[i] = ptr;
00212          ptr += 4;
00213          break;
00214        }
00215       ptr += 4;
00216 
00217       /* If we've handled more arguments than fit in registers,
00218         start looking at the those passed on the stack.  */
00219       if (ptr == ((char *)register_args + (6*4)))
00220        ptr = stack_args;
00221     }
00222 
00223   /* Invoke the closure.  */
00224   if (cif->rtype->type == FFI_TYPE_STRUCT)
00225     {
00226       /* The caller allocates space for the return structure, and
00227        passes a pointer to this space in gr3.  Use this value directly
00228        as the return value.  */
00229       register void *return_struct_ptr __asm__("gr3");
00230       (closure->fun) (cif, return_struct_ptr, avalue, closure->user_data);
00231     }
00232   else
00233     {
00234       /* Allocate space for the return value and call the function.  */
00235       long long rvalue;
00236       (closure->fun) (cif, &rvalue, avalue, closure->user_data);
00237 
00238       /* Functions return 4-byte or smaller results in gr8.  8-byte
00239         values also use gr9.  We fill the both, even for small return
00240         values, just to avoid a branch.  */ 
00241       asm ("ldi  @(%0, #0), gr8" : : "r" (&rvalue));
00242       asm ("ldi  @(%0, #0), gr9" : : "r" (&((int *) &rvalue)[1]));
00243     }
00244 }
00245 
00246 ffi_status
00247 ffi_prep_closure_loc (ffi_closure* closure,
00248                     ffi_cif* cif,
00249                     void (*fun)(ffi_cif*, void*, void**, void*),
00250                     void *user_data,
00251                     void *codeloc)
00252 {
00253   unsigned int *tramp = (unsigned int *) &closure->tramp[0];
00254   unsigned long fn = (long) ffi_closure_eabi;
00255   unsigned long cls = (long) codeloc;
00256 #ifdef __FRV_FDPIC__
00257   register void *got __asm__("gr15");
00258 #endif
00259   int i;
00260 
00261   fn = (unsigned long) ffi_closure_eabi;
00262 
00263 #ifdef __FRV_FDPIC__
00264   tramp[0] = &((unsigned int *)codeloc)[2];
00265   tramp[1] = got;
00266   tramp[2] = 0x8cfc0000 + (fn  & 0xffff); /* setlos lo(fn), gr6    */
00267   tramp[3] = 0x8efc0000 + (cls & 0xffff); /* setlos lo(cls), gr7   */
00268   tramp[4] = 0x8cf80000 + (fn  >> 16);      /* sethi hi(fn), gr6     */
00269   tramp[5] = 0x8ef80000 + (cls >> 16);    /* sethi hi(cls), gr7    */
00270   tramp[6] = 0x9cc86000;                  /* ldi @(gr6, #0), gr14  */
00271   tramp[7] = 0x8030e000;                  /* jmpl @(gr14, gr0)     */
00272 #else
00273   tramp[0] = 0x8cfc0000 + (fn  & 0xffff); /* setlos lo(fn), gr6    */
00274   tramp[1] = 0x8efc0000 + (cls & 0xffff); /* setlos lo(cls), gr7   */
00275   tramp[2] = 0x8cf80000 + (fn  >> 16);      /* sethi hi(fn), gr6     */
00276   tramp[3] = 0x8ef80000 + (cls >> 16);    /* sethi hi(cls), gr7    */
00277   tramp[4] = 0x80300006;                  /* jmpl @(gr0, gr6)      */
00278 #endif
00279 
00280   closure->cif = cif;
00281   closure->fun = fun;
00282   closure->user_data = user_data;
00283 
00284   /* Cache flushing.  */
00285   for (i = 0; i < FFI_TRAMPOLINE_SIZE; i++)
00286     __asm__ volatile ("dcf @(%0,%1)\n\tici @(%2,%1)" :: "r" (tramp), "r" (i),
00287                     "r" (codeloc));
00288 
00289   return FFI_OK;
00290 }