Back to index

plt-scheme  4.2.1
ffi.c
Go to the documentation of this file.
00001 /* -----------------------------------------------------------------------
00002    ffi.c - Copyright (c) 1996, 2007 Red Hat, Inc.
00003    
00004    MIPS 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 #ifdef FFI_DEBUG
00032 # define FFI_MIPS_STOP_HERE() ffi_stop_here()
00033 #else
00034 # define FFI_MIPS_STOP_HERE() do {} while(0)
00035 #endif
00036 
00037 #ifdef FFI_MIPS_N32
00038 #define FIX_ARGP \
00039 FFI_ASSERT(argp <= &stack[bytes]); \
00040 if (argp == &stack[bytes]) \
00041 { \
00042   argp = stack; \
00043   FFI_MIPS_STOP_HERE(); \
00044 }
00045 #else
00046 #define FIX_ARGP 
00047 #endif
00048 
00049 
00050 /* ffi_prep_args is called by the assembly routine once stack space
00051    has been allocated for the function's arguments */
00052 
00053 static void ffi_prep_args(char *stack, 
00054                        extended_cif *ecif,
00055                        int bytes,
00056                        int flags)
00057 {
00058   int i;
00059   void **p_argv;
00060   char *argp;
00061   ffi_type **p_arg;
00062 
00063 #ifdef FFI_MIPS_N32
00064   /* If more than 8 double words are used, the remainder go
00065      on the stack. We reorder stuff on the stack here to 
00066      support this easily. */
00067   if (bytes > 8 * sizeof(ffi_arg))
00068     argp = &stack[bytes - (8 * sizeof(ffi_arg))];
00069   else
00070     argp = stack;
00071 #else
00072   argp = stack;
00073 #endif
00074 
00075   memset(stack, 0, bytes);
00076 
00077 #ifdef FFI_MIPS_N32
00078   if ( ecif->cif->rstruct_flag != 0 )
00079 #else
00080   if ( ecif->cif->rtype->type == FFI_TYPE_STRUCT )
00081 #endif  
00082     {
00083       *(ffi_arg *) argp = (ffi_arg) ecif->rvalue;
00084       argp += sizeof(ffi_arg);
00085       FIX_ARGP;
00086     }
00087 
00088   p_argv = ecif->avalue;
00089 
00090   for (i = ecif->cif->nargs, p_arg = ecif->cif->arg_types; i; i--, p_arg++)
00091     {
00092       size_t z;
00093       unsigned int a;
00094 
00095       /* Align if necessary.  */
00096       a = (*p_arg)->alignment;
00097       if (a < sizeof(ffi_arg))
00098         a = sizeof(ffi_arg);
00099       
00100       if ((a - 1) & (unsigned long) argp)
00101        {
00102          argp = (char *) ALIGN(argp, a);
00103          FIX_ARGP;
00104        }
00105 
00106       z = (*p_arg)->size;
00107       if (z <= sizeof(ffi_arg))
00108        {
00109           int type = (*p_arg)->type;
00110          z = sizeof(ffi_arg);
00111 
00112           /* The size of a pointer depends on the ABI */
00113           if (type == FFI_TYPE_POINTER)
00114             type =
00115               (ecif->cif->abi == FFI_N64) ? FFI_TYPE_SINT64 : FFI_TYPE_SINT32;
00116 
00117          switch (type)
00118            {
00119              case FFI_TYPE_SINT8:
00120               *(ffi_arg *)argp = *(SINT8 *)(* p_argv);
00121               break;
00122 
00123              case FFI_TYPE_UINT8:
00124               *(ffi_arg *)argp = *(UINT8 *)(* p_argv);
00125               break;
00126                 
00127              case FFI_TYPE_SINT16:
00128               *(ffi_arg *)argp = *(SINT16 *)(* p_argv);
00129               break;
00130                 
00131              case FFI_TYPE_UINT16:
00132               *(ffi_arg *)argp = *(UINT16 *)(* p_argv);
00133               break;
00134                 
00135              case FFI_TYPE_SINT32:
00136               *(ffi_arg *)argp = *(SINT32 *)(* p_argv);
00137               break;
00138                 
00139              case FFI_TYPE_UINT32:
00140               *(ffi_arg *)argp = *(UINT32 *)(* p_argv);
00141               break;
00142 
00143              /* This can only happen with 64bit slots.  */
00144              case FFI_TYPE_FLOAT:
00145               *(float *) argp = *(float *)(* p_argv);
00146               break;
00147 
00148              /* Handle structures.  */
00149              default:
00150               memcpy(argp, *p_argv, (*p_arg)->size);
00151               break;
00152            }
00153        }
00154       else
00155        {
00156 #ifdef FFI_MIPS_O32
00157          memcpy(argp, *p_argv, z);
00158 #else
00159          {
00160            unsigned long end = (unsigned long) argp + z;
00161            unsigned long cap = (unsigned long) stack + bytes;
00162 
00163            /* Check if the data will fit within the register space.
00164               Handle it if it doesn't.  */
00165 
00166            if (end <= cap)
00167              memcpy(argp, *p_argv, z);
00168            else
00169              {
00170               unsigned long portion = cap - (unsigned long)argp;
00171 
00172               memcpy(argp, *p_argv, portion);
00173               argp = stack;
00174                 z -= portion;
00175               memcpy(argp, (void*)((unsigned long)(*p_argv) + portion),
00176                        z);
00177              }
00178          }
00179 #endif
00180       }
00181       p_argv++;
00182       argp += z;
00183       FIX_ARGP;
00184     }
00185 }
00186 
00187 #ifdef FFI_MIPS_N32
00188 
00189 /* The n32 spec says that if "a chunk consists solely of a double 
00190    float field (but not a double, which is part of a union), it
00191    is passed in a floating point register. Any other chunk is
00192    passed in an integer register". This code traverses structure
00193    definitions and generates the appropriate flags. */
00194 
00195 static unsigned
00196 calc_n32_struct_flags(ffi_type *arg, unsigned *loc, unsigned *arg_reg)
00197 {
00198   unsigned flags = 0;
00199   unsigned index = 0;
00200 
00201   ffi_type *e;
00202 
00203   while ((e = arg->elements[index]))
00204     {
00205       /* Align this object.  */
00206       *loc = ALIGN(*loc, e->alignment);
00207       if (e->type == FFI_TYPE_DOUBLE)
00208        {
00209           /* Already aligned to FFI_SIZEOF_ARG.  */
00210           *arg_reg = *loc / FFI_SIZEOF_ARG;
00211           if (*arg_reg > 7)
00212             break;
00213          flags += (FFI_TYPE_DOUBLE << (*arg_reg * FFI_FLAG_BITS));
00214           *loc += e->size;
00215        }
00216       else
00217         *loc += e->size;
00218       index++;
00219     }
00220   /* Next Argument register at alignment of FFI_SIZEOF_ARG.  */
00221   *arg_reg = ALIGN(*loc, FFI_SIZEOF_ARG) / FFI_SIZEOF_ARG;
00222 
00223   return flags;
00224 }
00225 
00226 static unsigned
00227 calc_n32_return_struct_flags(ffi_type *arg)
00228 {
00229   unsigned flags = 0;
00230   unsigned small = FFI_TYPE_SMALLSTRUCT;
00231   ffi_type *e;
00232 
00233   /* Returning structures under n32 is a tricky thing.
00234      A struct with only one or two floating point fields 
00235      is returned in $f0 (and $f2 if necessary). Any other
00236      struct results at most 128 bits are returned in $2
00237      (the first 64 bits) and $3 (remainder, if necessary).
00238      Larger structs are handled normally. */
00239   
00240   if (arg->size > 16)
00241     return 0;
00242 
00243   if (arg->size > 8)
00244     small = FFI_TYPE_SMALLSTRUCT2;
00245 
00246   e = arg->elements[0];
00247   if (e->type == FFI_TYPE_DOUBLE)
00248     flags = FFI_TYPE_DOUBLE;
00249   else if (e->type == FFI_TYPE_FLOAT)
00250     flags = FFI_TYPE_FLOAT;
00251 
00252   if (flags && (e = arg->elements[1]))
00253     {
00254       if (e->type == FFI_TYPE_DOUBLE)
00255        flags += FFI_TYPE_DOUBLE << FFI_FLAG_BITS;
00256       else if (e->type == FFI_TYPE_FLOAT)
00257        flags += FFI_TYPE_FLOAT << FFI_FLAG_BITS;
00258       else 
00259        return small;
00260 
00261       if (flags && (arg->elements[2]))
00262        {
00263          /* There are three arguments and the first two are 
00264             floats! This must be passed the old way. */
00265          return small;
00266        }
00267     }
00268   else
00269     if (!flags)
00270       return small;
00271 
00272   return flags;
00273 }
00274 
00275 #endif
00276 
00277 /* Perform machine dependent cif processing */
00278 ffi_status ffi_prep_cif_machdep(ffi_cif *cif)
00279 {
00280   cif->flags = 0;
00281 
00282 #ifdef FFI_MIPS_O32
00283   /* Set the flags necessary for O32 processing.  FFI_O32_SOFT_FLOAT
00284    * does not have special handling for floating point args.
00285    */
00286 
00287   if (cif->rtype->type != FFI_TYPE_STRUCT && cif->abi == FFI_O32)
00288     {
00289       if (cif->nargs > 0)
00290        {
00291          switch ((cif->arg_types)[0]->type)
00292            {
00293            case FFI_TYPE_FLOAT:
00294            case FFI_TYPE_DOUBLE:
00295              cif->flags += (cif->arg_types)[0]->type;
00296              break;
00297              
00298            default:
00299              break;
00300            }
00301 
00302          if (cif->nargs > 1)
00303            {
00304              /* Only handle the second argument if the first
00305                is a float or double. */
00306              if (cif->flags)
00307               {
00308                 switch ((cif->arg_types)[1]->type)
00309                   {
00310                   case FFI_TYPE_FLOAT:
00311                   case FFI_TYPE_DOUBLE:
00312                     cif->flags += (cif->arg_types)[1]->type << FFI_FLAG_BITS;
00313                     break;
00314                     
00315                   default:
00316                     break;
00317                   }
00318               }
00319            }
00320        }
00321     }
00322       
00323   /* Set the return type flag */
00324 
00325   if (cif->abi == FFI_O32_SOFT_FLOAT)
00326     {
00327       switch (cif->rtype->type)
00328         {
00329         case FFI_TYPE_VOID:
00330         case FFI_TYPE_STRUCT:
00331           cif->flags += cif->rtype->type << (FFI_FLAG_BITS * 2);
00332           break;
00333 
00334         case FFI_TYPE_SINT64:
00335         case FFI_TYPE_UINT64:
00336         case FFI_TYPE_DOUBLE:
00337           cif->flags += FFI_TYPE_UINT64 << (FFI_FLAG_BITS * 2);
00338           break;
00339       
00340         case FFI_TYPE_FLOAT:
00341         default:
00342           cif->flags += FFI_TYPE_INT << (FFI_FLAG_BITS * 2);
00343           break;
00344         }
00345     }
00346   else
00347     {
00348       /* FFI_O32 */      
00349       switch (cif->rtype->type)
00350         {
00351         case FFI_TYPE_VOID:
00352         case FFI_TYPE_STRUCT:
00353         case FFI_TYPE_FLOAT:
00354         case FFI_TYPE_DOUBLE:
00355           cif->flags += cif->rtype->type << (FFI_FLAG_BITS * 2);
00356           break;
00357 
00358         case FFI_TYPE_SINT64:
00359         case FFI_TYPE_UINT64:
00360           cif->flags += FFI_TYPE_UINT64 << (FFI_FLAG_BITS * 2);
00361           break;
00362       
00363         default:
00364           cif->flags += FFI_TYPE_INT << (FFI_FLAG_BITS * 2);
00365           break;
00366         }
00367     }
00368 #endif
00369 
00370 #ifdef FFI_MIPS_N32
00371   /* Set the flags necessary for N32 processing */
00372   {
00373     unsigned arg_reg = 0;
00374     unsigned loc = 0;
00375     unsigned count = (cif->nargs < 8) ? cif->nargs : 8;
00376     unsigned index = 0;
00377 
00378     unsigned struct_flags = 0;
00379 
00380     if (cif->rtype->type == FFI_TYPE_STRUCT)
00381       {
00382        struct_flags = calc_n32_return_struct_flags(cif->rtype);
00383 
00384        if (struct_flags == 0)
00385          {
00386            /* This means that the structure is being passed as
00387               a hidden argument */
00388 
00389            arg_reg = 1;
00390            count = (cif->nargs < 7) ? cif->nargs : 7;
00391 
00392            cif->rstruct_flag = !0;
00393          }
00394        else
00395            cif->rstruct_flag = 0;
00396       }
00397     else
00398       cif->rstruct_flag = 0;
00399 
00400     while (count-- > 0 && arg_reg < 8)
00401       {
00402        switch ((cif->arg_types)[index]->type)
00403          {
00404          case FFI_TYPE_FLOAT:
00405          case FFI_TYPE_DOUBLE:
00406            cif->flags +=
00407               ((cif->arg_types)[index]->type << (arg_reg * FFI_FLAG_BITS));
00408            arg_reg++;
00409            break;
00410           case FFI_TYPE_LONGDOUBLE:
00411             /* Align it.  */
00412             arg_reg = ALIGN(arg_reg, 2);
00413             /* Treat it as two adjacent doubles.  */
00414            cif->flags +=
00415               (FFI_TYPE_DOUBLE << (arg_reg * FFI_FLAG_BITS));
00416             arg_reg++;
00417            cif->flags +=
00418               (FFI_TYPE_DOUBLE << (arg_reg * FFI_FLAG_BITS));
00419             arg_reg++;
00420             break;
00421 
00422          case FFI_TYPE_STRUCT:
00423             loc = arg_reg * FFI_SIZEOF_ARG;
00424            cif->flags += calc_n32_struct_flags((cif->arg_types)[index],
00425                                           &loc, &arg_reg);
00426            break;
00427 
00428          default:
00429            arg_reg++;
00430             break;
00431          }
00432 
00433        index++;
00434       }
00435 
00436   /* Set the return type flag */
00437     switch (cif->rtype->type)
00438       {
00439       case FFI_TYPE_STRUCT:
00440        {
00441          if (struct_flags == 0)
00442            {
00443              /* The structure is returned through a hidden
00444                first argument. Do nothing, 'cause FFI_TYPE_VOID 
00445                is 0 */
00446            }
00447          else
00448            {
00449              /* The structure is returned via some tricky
00450                mechanism */
00451              cif->flags += FFI_TYPE_STRUCT << (FFI_FLAG_BITS * 8);
00452              cif->flags += struct_flags << (4 + (FFI_FLAG_BITS * 8));
00453            }
00454          break;
00455        }
00456       
00457       case FFI_TYPE_VOID:
00458        /* Do nothing, 'cause FFI_TYPE_VOID is 0 */
00459        break;
00460        
00461       case FFI_TYPE_FLOAT:
00462       case FFI_TYPE_DOUBLE:
00463        cif->flags += cif->rtype->type << (FFI_FLAG_BITS * 8);
00464        break;
00465       case FFI_TYPE_LONGDOUBLE:
00466        /* Long double is returned as if it were a struct containing
00467           two doubles.  */
00468        cif->flags += FFI_TYPE_STRUCT << (FFI_FLAG_BITS * 8);
00469        cif->flags += (FFI_TYPE_DOUBLE + (FFI_TYPE_DOUBLE << FFI_FLAG_BITS))
00470                     << (4 + (FFI_FLAG_BITS * 8));
00471        break;
00472       default:
00473        cif->flags += FFI_TYPE_INT << (FFI_FLAG_BITS * 8);
00474        break;
00475       }
00476   }
00477 #endif
00478   
00479   return FFI_OK;
00480 }
00481 
00482 /* Low level routine for calling O32 functions */
00483 extern int ffi_call_O32(void (*)(char *, extended_cif *, int, int), 
00484                      extended_cif *, unsigned, 
00485                      unsigned, unsigned *, void (*)());
00486 
00487 /* Low level routine for calling N32 functions */
00488 extern int ffi_call_N32(void (*)(char *, extended_cif *, int, int), 
00489                      extended_cif *, unsigned, 
00490                      unsigned, unsigned *, void (*)());
00491 
00492 void ffi_call(ffi_cif *cif, void (*fn)(), void *rvalue, void **avalue)
00493 {
00494   extended_cif ecif;
00495 
00496   ecif.cif = cif;
00497   ecif.avalue = avalue;
00498   
00499   /* If the return value is a struct and we don't have a return       */
00500   /* value address then we need to make one                     */
00501   
00502   if ((rvalue == NULL) && 
00503       (cif->rtype->type == FFI_TYPE_STRUCT))
00504     ecif.rvalue = alloca(cif->rtype->size);
00505   else
00506     ecif.rvalue = rvalue;
00507     
00508   switch (cif->abi) 
00509     {
00510 #ifdef FFI_MIPS_O32
00511     case FFI_O32:
00512     case FFI_O32_SOFT_FLOAT:
00513       ffi_call_O32(ffi_prep_args, &ecif, cif->bytes, 
00514                  cif->flags, ecif.rvalue, fn);
00515       break;
00516 #endif
00517 
00518 #ifdef FFI_MIPS_N32
00519     case FFI_N32:
00520     case FFI_N64:
00521       {
00522         int copy_rvalue = 0;
00523         void *rvalue_copy = ecif.rvalue;
00524         if (cif->rtype->type == FFI_TYPE_STRUCT && cif->rtype->size < 16)
00525           {
00526             /* For structures smaller than 16 bytes we clobber memory
00527                in 8 byte increments.  Make a copy so we don't clobber
00528                the callers memory outside of the struct bounds.  */
00529             rvalue_copy = alloca(16);
00530             copy_rvalue = 1;
00531           }
00532         ffi_call_N32(ffi_prep_args, &ecif, cif->bytes,
00533                      cif->flags, rvalue_copy, fn);
00534         if (copy_rvalue)
00535           memcpy(ecif.rvalue, rvalue_copy, cif->rtype->size);
00536       }
00537       break;
00538 #endif
00539 
00540     default:
00541       FFI_ASSERT(0);
00542       break;
00543     }
00544 }
00545 
00546 #if FFI_CLOSURES
00547 #if defined(FFI_MIPS_O32)
00548 extern void ffi_closure_O32(void);
00549 #else
00550 extern void ffi_closure_N32(void);
00551 #endif /* FFI_MIPS_O32 */
00552 
00553 ffi_status
00554 ffi_prep_closure_loc (ffi_closure *closure,
00555                     ffi_cif *cif,
00556                     void (*fun)(ffi_cif*,void*,void**,void*),
00557                     void *user_data,
00558                     void *codeloc)
00559 {
00560   unsigned int *tramp = (unsigned int *) &closure->tramp[0];
00561   void * fn;
00562   char *clear_location = (char *) codeloc;
00563 
00564 #if defined(FFI_MIPS_O32)
00565   FFI_ASSERT(cif->abi == FFI_O32 || cif->abi == FFI_O32_SOFT_FLOAT);
00566   fn = ffi_closure_O32;
00567 #else /* FFI_MIPS_N32 */
00568   FFI_ASSERT(cif->abi == FFI_N32 || cif->abi == FFI_N64);
00569   fn = ffi_closure_N32;
00570 #endif /* FFI_MIPS_O32 */
00571 
00572 #if defined(FFI_MIPS_O32) || (_MIPS_SIM ==_ABIN32)
00573   /* lui  $25,high(fn) */
00574   tramp[0] = 0x3c190000 | ((unsigned)fn >> 16);
00575   /* ori  $25,low(fn)  */
00576   tramp[1] = 0x37390000 | ((unsigned)fn & 0xffff);
00577   /* lui  $12,high(codeloc) */
00578   tramp[2] = 0x3c0c0000 | ((unsigned)codeloc >> 16);
00579   /* jr   $25          */
00580   tramp[3] = 0x03200008;
00581   /* ori  $12,low(codeloc)  */
00582   tramp[4] = 0x358c0000 | ((unsigned)codeloc & 0xffff);
00583 #else
00584   /* N64 has a somewhat larger trampoline.  */
00585   /* lui  $25,high(fn) */
00586   tramp[0] = 0x3c190000 | ((unsigned long)fn >> 48);
00587   /* lui  $12,high(codeloc) */
00588   tramp[1] = 0x3c0c0000 | ((unsigned long)codeloc >> 48);
00589   /* ori  $25,mid-high(fn)  */
00590   tramp[2] = 0x37390000 | (((unsigned long)fn >> 32 ) & 0xffff);
00591   /* ori  $12,mid-high(codeloc)  */
00592   tramp[3] = 0x358c0000 | (((unsigned long)codeloc >> 32) & 0xffff);
00593   /* dsll $25,$25,16 */
00594   tramp[4] = 0x0019cc38;
00595   /* dsll $12,$12,16 */
00596   tramp[5] = 0x000c6438;
00597   /* ori  $25,mid-low(fn)  */
00598   tramp[6] = 0x37390000 | (((unsigned long)fn >> 16 ) & 0xffff);
00599   /* ori  $12,mid-low(codeloc)  */
00600   tramp[7] = 0x358c0000 | (((unsigned long)codeloc >> 16) & 0xffff);
00601   /* dsll $25,$25,16 */
00602   tramp[8] = 0x0019cc38;
00603   /* dsll $12,$12,16 */
00604   tramp[9] = 0x000c6438;
00605   /* ori  $25,low(fn)  */
00606   tramp[10] = 0x37390000 | ((unsigned long)fn  & 0xffff);
00607   /* jr   $25          */
00608   tramp[11] = 0x03200008;
00609   /* ori  $12,low(codeloc)  */
00610   tramp[12] = 0x358c0000 | ((unsigned long)codeloc & 0xffff);
00611 
00612 #endif
00613 
00614   closure->cif = cif;
00615   closure->fun = fun;
00616   closure->user_data = user_data;
00617 
00618   __builtin___clear_cache(clear_location, clear_location + FFI_TRAMPOLINE_SIZE);
00619 
00620   return FFI_OK;
00621 }
00622 
00623 /*
00624  * Decodes the arguments to a function, which will be stored on the
00625  * stack. AR is the pointer to the beginning of the integer arguments
00626  * (and, depending upon the arguments, some floating-point arguments
00627  * as well). FPR is a pointer to the area where floating point
00628  * registers have been saved, if any.
00629  *
00630  * RVALUE is the location where the function return value will be
00631  * stored. CLOSURE is the prepared closure to invoke.
00632  *
00633  * This function should only be called from assembly, which is in
00634  * turn called from a trampoline.
00635  *
00636  * Returns the function return type.
00637  *
00638  * Based on the similar routine for sparc.
00639  */
00640 int
00641 ffi_closure_mips_inner_O32 (ffi_closure *closure,
00642                          void *rvalue, ffi_arg *ar,
00643                          double *fpr)
00644 {
00645   ffi_cif *cif;
00646   void **avaluep;
00647   ffi_arg *avalue;
00648   ffi_type **arg_types;
00649   int i, avn, argn, seen_int;
00650 
00651   cif = closure->cif;
00652   avalue = alloca (cif->nargs * sizeof (ffi_arg));
00653   avaluep = alloca (cif->nargs * sizeof (ffi_arg));
00654 
00655   seen_int = (cif->abi == FFI_O32_SOFT_FLOAT);
00656   argn = 0;
00657 
00658   if ((cif->flags >> (FFI_FLAG_BITS * 2)) == FFI_TYPE_STRUCT)
00659     {
00660       rvalue = (void *)(UINT32)ar[0];
00661       argn = 1;
00662     }
00663 
00664   i = 0;
00665   avn = cif->nargs;
00666   arg_types = cif->arg_types;
00667 
00668   while (i < avn)
00669     {
00670       if (i < 2 && !seen_int &&
00671          (arg_types[i]->type == FFI_TYPE_FLOAT ||
00672           arg_types[i]->type == FFI_TYPE_DOUBLE))
00673        {
00674 #ifdef __MIPSEB__
00675          if (arg_types[i]->type == FFI_TYPE_FLOAT)
00676            avaluep[i] = ((char *) &fpr[i]) + sizeof (float);
00677          else
00678 #endif
00679            avaluep[i] = (char *) &fpr[i];
00680        }
00681       else
00682        {
00683          if (arg_types[i]->alignment == 8 && (argn & 0x1))
00684            argn++;
00685          switch (arg_types[i]->type)
00686            {
00687              case FFI_TYPE_SINT8:
00688               avaluep[i] = &avalue[i];
00689               *(SINT8 *) &avalue[i] = (SINT8) ar[argn];
00690               break;
00691 
00692              case FFI_TYPE_UINT8:
00693               avaluep[i] = &avalue[i];
00694               *(UINT8 *) &avalue[i] = (UINT8) ar[argn];
00695               break;
00696                 
00697              case FFI_TYPE_SINT16:
00698               avaluep[i] = &avalue[i];
00699               *(SINT16 *) &avalue[i] = (SINT16) ar[argn];
00700               break;
00701                 
00702              case FFI_TYPE_UINT16:
00703               avaluep[i] = &avalue[i];
00704               *(UINT16 *) &avalue[i] = (UINT16) ar[argn];
00705               break;
00706 
00707              default:
00708               avaluep[i] = (char *) &ar[argn];
00709               break;
00710            }
00711          seen_int = 1;
00712        }
00713       argn += ALIGN(arg_types[i]->size, FFI_SIZEOF_ARG) / FFI_SIZEOF_ARG;
00714       i++;
00715     }
00716 
00717   /* Invoke the closure. */
00718   (closure->fun) (cif, rvalue, avaluep, closure->user_data);
00719 
00720   if (cif->abi == FFI_O32_SOFT_FLOAT)
00721     {
00722       switch (cif->rtype->type)
00723         {
00724         case FFI_TYPE_FLOAT:
00725           return FFI_TYPE_INT;
00726         case FFI_TYPE_DOUBLE:
00727           return FFI_TYPE_UINT64;
00728         default:
00729           return cif->rtype->type;
00730         }
00731     }
00732   else
00733     {
00734       return cif->rtype->type;
00735     }
00736 }
00737 
00738 #if defined(FFI_MIPS_N32)
00739 
00740 static void
00741 copy_struct_N32(char *target, unsigned offset, ffi_abi abi, ffi_type *type,
00742                 int argn, unsigned arg_offset, ffi_arg *ar,
00743                 ffi_arg *fpr)
00744 {
00745   ffi_type **elt_typep = type->elements;
00746   while(*elt_typep)
00747     {
00748       ffi_type *elt_type = *elt_typep;
00749       unsigned o;
00750       char *tp;
00751       char *argp;
00752       char *fpp;
00753 
00754       o = ALIGN(offset, elt_type->alignment);
00755       arg_offset += o - offset;
00756       offset = o;
00757       argn += arg_offset / sizeof(ffi_arg);
00758       arg_offset = arg_offset % sizeof(ffi_arg);
00759 
00760       argp = (char *)(ar + argn);
00761       fpp = (char *)(argn >= 8 ? ar + argn : fpr + argn);
00762 
00763       tp = target + offset;
00764 
00765       if (elt_type->type == FFI_TYPE_DOUBLE)
00766         *(double *)tp = *(double *)fpp;
00767       else
00768         memcpy(tp, argp + arg_offset, elt_type->size);
00769 
00770       offset += elt_type->size;
00771       arg_offset += elt_type->size;
00772       elt_typep++;
00773       argn += arg_offset / sizeof(ffi_arg);
00774       arg_offset = arg_offset % sizeof(ffi_arg);
00775     }
00776 }
00777 
00778 /*
00779  * Decodes the arguments to a function, which will be stored on the
00780  * stack. AR is the pointer to the beginning of the integer
00781  * arguments. FPR is a pointer to the area where floating point
00782  * registers have been saved.
00783  *
00784  * RVALUE is the location where the function return value will be
00785  * stored. CLOSURE is the prepared closure to invoke.
00786  *
00787  * This function should only be called from assembly, which is in
00788  * turn called from a trampoline.
00789  *
00790  * Returns the function return flags.
00791  *
00792  */
00793 int
00794 ffi_closure_mips_inner_N32 (ffi_closure *closure,
00795                          void *rvalue, ffi_arg *ar,
00796                          ffi_arg *fpr)
00797 {
00798   ffi_cif *cif;
00799   void **avaluep;
00800   ffi_arg *avalue;
00801   ffi_type **arg_types;
00802   int i, avn, argn;
00803 
00804   cif = closure->cif;
00805   avalue = alloca (cif->nargs * sizeof (ffi_arg));
00806   avaluep = alloca (cif->nargs * sizeof (ffi_arg));
00807 
00808   argn = 0;
00809 
00810   if (cif->rstruct_flag)
00811     {
00812 #if _MIPS_SIM==_ABIN32
00813       rvalue = (void *)(UINT32)ar[0];
00814 #else /* N64 */
00815       rvalue = (void *)ar[0];
00816 #endif
00817       argn = 1;
00818     }
00819 
00820   i = 0;
00821   avn = cif->nargs;
00822   arg_types = cif->arg_types;
00823 
00824   while (i < avn)
00825     {
00826       if (arg_types[i]->type == FFI_TYPE_FLOAT
00827           || arg_types[i]->type == FFI_TYPE_DOUBLE)
00828         {
00829           ffi_arg *argp = argn >= 8 ? ar + argn : fpr + argn;
00830 #ifdef __MIPSEB__
00831           if (arg_types[i]->type == FFI_TYPE_FLOAT && argn < 8)
00832             avaluep[i] = ((char *) argp) + sizeof (float);
00833           else
00834 #endif
00835             avaluep[i] = (char *) argp;
00836         }
00837       else
00838         {
00839           unsigned type = arg_types[i]->type;
00840 
00841           if (arg_types[i]->alignment > sizeof(ffi_arg))
00842             argn = ALIGN(argn, arg_types[i]->alignment / sizeof(ffi_arg));
00843 
00844           ffi_arg *argp = ar + argn;
00845 
00846           /* The size of a pointer depends on the ABI */
00847           if (type == FFI_TYPE_POINTER)
00848             type = (cif->abi == FFI_N64) ? FFI_TYPE_SINT64 : FFI_TYPE_SINT32;
00849 
00850           switch (type)
00851             {
00852             case FFI_TYPE_SINT8:
00853               avaluep[i] = &avalue[i];
00854               *(SINT8 *) &avalue[i] = (SINT8) *argp;
00855               break;
00856 
00857             case FFI_TYPE_UINT8:
00858               avaluep[i] = &avalue[i];
00859               *(UINT8 *) &avalue[i] = (UINT8) *argp;
00860               break;
00861 
00862             case FFI_TYPE_SINT16:
00863               avaluep[i] = &avalue[i];
00864               *(SINT16 *) &avalue[i] = (SINT16) *argp;
00865               break;
00866 
00867             case FFI_TYPE_UINT16:
00868               avaluep[i] = &avalue[i];
00869               *(UINT16 *) &avalue[i] = (UINT16) *argp;
00870               break;
00871 
00872             case FFI_TYPE_SINT32:
00873               avaluep[i] = &avalue[i];
00874               *(SINT32 *) &avalue[i] = (SINT32) *argp;
00875               break;
00876 
00877             case FFI_TYPE_UINT32:
00878               avaluep[i] = &avalue[i];
00879               *(UINT32 *) &avalue[i] = (UINT32) *argp;
00880               break;
00881 
00882             case FFI_TYPE_STRUCT:
00883               if (argn < 8)
00884                 {
00885                   /* Allocate space for the struct as at least part of
00886                      it was passed in registers.  */
00887                   avaluep[i] = alloca(arg_types[i]->size);
00888                   copy_struct_N32(avaluep[i], 0, cif->abi, arg_types[i],
00889                                   argn, 0, ar, fpr);
00890 
00891                   break;
00892                 }
00893               /* Else fall through.  */
00894             default:
00895               avaluep[i] = (char *) argp;
00896               break;
00897             }
00898         }
00899       argn += ALIGN(arg_types[i]->size, sizeof(ffi_arg)) / sizeof(ffi_arg);
00900       i++;
00901     }
00902 
00903   /* Invoke the closure. */
00904   (closure->fun) (cif, rvalue, avaluep, closure->user_data);
00905 
00906   return cif->flags >> (FFI_FLAG_BITS * 8);
00907 }
00908 
00909 #endif /* FFI_MIPS_N32 */
00910 
00911 #endif /* FFI_CLOSURES */