LCOV - code coverage report
Current view: top level - js/src/ctypes/libffi/src/x86 - ffi64.c (source / functions) Hit Total Coverage
Test: output.info Lines: 0 250 0.0 %
Date: 2017-07-14 16:53:18 Functions: 0 7 0.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -----------------------------------------------------------------------
       2             :    ffi64.c - Copyright (c) 2013  The Written Word, Inc.
       3             :              Copyright (c) 2011  Anthony Green
       4             :              Copyright (c) 2008, 2010  Red Hat, Inc.
       5             :              Copyright (c) 2002, 2007  Bo Thorsen <bo@suse.de>
       6             : 
       7             :    x86-64 Foreign Function Interface
       8             : 
       9             :    Permission is hereby granted, free of charge, to any person obtaining
      10             :    a copy of this software and associated documentation files (the
      11             :    ``Software''), to deal in the Software without restriction, including
      12             :    without limitation the rights to use, copy, modify, merge, publish,
      13             :    distribute, sublicense, and/or sell copies of the Software, and to
      14             :    permit persons to whom the Software is furnished to do so, subject to
      15             :    the following conditions:
      16             : 
      17             :    The above copyright notice and this permission notice shall be included
      18             :    in all copies or substantial portions of the Software.
      19             : 
      20             :    THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND,
      21             :    EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
      22             :    MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
      23             :    NONINFRINGEMENT.  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
      24             :    HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
      25             :    WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
      26             :    OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
      27             :    DEALINGS IN THE SOFTWARE.
      28             :    ----------------------------------------------------------------------- */
      29             : 
      30             : #include <ffi.h>
      31             : #include <ffi_common.h>
      32             : 
      33             : #include <stdlib.h>
      34             : #include <stdarg.h>
      35             : 
      36             : #ifdef __x86_64__
      37             : 
      38             : #define MAX_GPR_REGS 6
      39             : #define MAX_SSE_REGS 8
      40             : 
      41             : #if defined(__INTEL_COMPILER)
      42             : #include "xmmintrin.h"
      43             : #define UINT128 __m128
      44             : #else
      45             : #if defined(__SUNPRO_C)
      46             : #include <sunmedia_types.h>
      47             : #define UINT128 __m128i
      48             : #else
      49             : #define UINT128 __int128_t
      50             : #endif
      51             : #endif
      52             : 
      53             : union big_int_union
      54             : {
      55             :   UINT32 i32;
      56             :   UINT64 i64;
      57             :   UINT128 i128;
      58             : };
      59             : 
      60             : struct register_args
      61             : {
      62             :   /* Registers for argument passing.  */
      63             :   UINT64 gpr[MAX_GPR_REGS];
      64             :   union big_int_union sse[MAX_SSE_REGS];
      65             : };
      66             : 
      67             : extern void ffi_call_unix64 (void *args, unsigned long bytes, unsigned flags,
      68             :                              void *raddr, void (*fnaddr)(void), unsigned ssecount);
      69             : 
      70             : /* All reference to register classes here is identical to the code in
      71             :    gcc/config/i386/i386.c. Do *not* change one without the other.  */
      72             : 
      73             : /* Register class used for passing given 64bit part of the argument.
      74             :    These represent classes as documented by the PS ABI, with the
      75             :    exception of SSESF, SSEDF classes, that are basically SSE class,
      76             :    just gcc will use SF or DFmode move instead of DImode to avoid
      77             :    reformatting penalties.
      78             : 
      79             :    Similary we play games with INTEGERSI_CLASS to use cheaper SImode moves
      80             :    whenever possible (upper half does contain padding).  */
      81             : enum x86_64_reg_class
      82             :   {
      83             :     X86_64_NO_CLASS,
      84             :     X86_64_INTEGER_CLASS,
      85             :     X86_64_INTEGERSI_CLASS,
      86             :     X86_64_SSE_CLASS,
      87             :     X86_64_SSESF_CLASS,
      88             :     X86_64_SSEDF_CLASS,
      89             :     X86_64_SSEUP_CLASS,
      90             :     X86_64_X87_CLASS,
      91             :     X86_64_X87UP_CLASS,
      92             :     X86_64_COMPLEX_X87_CLASS,
      93             :     X86_64_MEMORY_CLASS
      94             :   };
      95             : 
      96             : #define MAX_CLASSES 4
      97             : 
      98             : #define SSE_CLASS_P(X)  ((X) >= X86_64_SSE_CLASS && X <= X86_64_SSEUP_CLASS)
      99             : 
     100             : /* x86-64 register passing implementation.  See x86-64 ABI for details.  Goal
     101             :    of this code is to classify each 8bytes of incoming argument by the register
     102             :    class and assign registers accordingly.  */
     103             : 
     104             : /* Return the union class of CLASS1 and CLASS2.
     105             :    See the x86-64 PS ABI for details.  */
     106             : 
     107             : static enum x86_64_reg_class
     108           0 : merge_classes (enum x86_64_reg_class class1, enum x86_64_reg_class class2)
     109             : {
     110             :   /* Rule #1: If both classes are equal, this is the resulting class.  */
     111           0 :   if (class1 == class2)
     112           0 :     return class1;
     113             : 
     114             :   /* Rule #2: If one of the classes is NO_CLASS, the resulting class is
     115             :      the other class.  */
     116           0 :   if (class1 == X86_64_NO_CLASS)
     117           0 :     return class2;
     118           0 :   if (class2 == X86_64_NO_CLASS)
     119           0 :     return class1;
     120             : 
     121             :   /* Rule #3: If one of the classes is MEMORY, the result is MEMORY.  */
     122           0 :   if (class1 == X86_64_MEMORY_CLASS || class2 == X86_64_MEMORY_CLASS)
     123           0 :     return X86_64_MEMORY_CLASS;
     124             : 
     125             :   /* Rule #4: If one of the classes is INTEGER, the result is INTEGER.  */
     126           0 :   if ((class1 == X86_64_INTEGERSI_CLASS && class2 == X86_64_SSESF_CLASS)
     127           0 :       || (class2 == X86_64_INTEGERSI_CLASS && class1 == X86_64_SSESF_CLASS))
     128           0 :     return X86_64_INTEGERSI_CLASS;
     129           0 :   if (class1 == X86_64_INTEGER_CLASS || class1 == X86_64_INTEGERSI_CLASS
     130           0 :       || class2 == X86_64_INTEGER_CLASS || class2 == X86_64_INTEGERSI_CLASS)
     131           0 :     return X86_64_INTEGER_CLASS;
     132             : 
     133             :   /* Rule #5: If one of the classes is X87, X87UP, or COMPLEX_X87 class,
     134             :      MEMORY is used.  */
     135           0 :   if (class1 == X86_64_X87_CLASS
     136           0 :       || class1 == X86_64_X87UP_CLASS
     137           0 :       || class1 == X86_64_COMPLEX_X87_CLASS
     138           0 :       || class2 == X86_64_X87_CLASS
     139           0 :       || class2 == X86_64_X87UP_CLASS
     140           0 :       || class2 == X86_64_COMPLEX_X87_CLASS)
     141           0 :     return X86_64_MEMORY_CLASS;
     142             : 
     143             :   /* Rule #6: Otherwise class SSE is used.  */
     144           0 :   return X86_64_SSE_CLASS;
     145             : }
     146             : 
     147             : /* Classify the argument of type TYPE and mode MODE.
     148             :    CLASSES will be filled by the register class used to pass each word
     149             :    of the operand.  The number of words is returned.  In case the parameter
     150             :    should be passed in memory, 0 is returned. As a special case for zero
     151             :    sized containers, classes[0] will be NO_CLASS and 1 is returned.
     152             : 
     153             :    See the x86-64 PS ABI for details.
     154             : */
     155             : static size_t
     156           0 : classify_argument (ffi_type *type, enum x86_64_reg_class classes[],
     157             :                    size_t byte_offset)
     158             : {
     159           0 :   switch (type->type)
     160             :     {
     161             :     case FFI_TYPE_UINT8:
     162             :     case FFI_TYPE_SINT8:
     163             :     case FFI_TYPE_UINT16:
     164             :     case FFI_TYPE_SINT16:
     165             :     case FFI_TYPE_UINT32:
     166             :     case FFI_TYPE_SINT32:
     167             :     case FFI_TYPE_UINT64:
     168             :     case FFI_TYPE_SINT64:
     169             :     case FFI_TYPE_POINTER:
     170             :       {
     171           0 :         size_t size = byte_offset + type->size;
     172             : 
     173           0 :         if (size <= 4)
     174             :           {
     175           0 :             classes[0] = X86_64_INTEGERSI_CLASS;
     176           0 :             return 1;
     177             :           }
     178           0 :         else if (size <= 8)
     179             :           {
     180           0 :             classes[0] = X86_64_INTEGER_CLASS;
     181           0 :             return 1;
     182             :           }
     183           0 :         else if (size <= 12)
     184             :           {
     185           0 :             classes[0] = X86_64_INTEGER_CLASS;
     186           0 :             classes[1] = X86_64_INTEGERSI_CLASS;
     187           0 :             return 2;
     188             :           }
     189           0 :         else if (size <= 16)
     190             :           {
     191           0 :             classes[0] = classes[1] = X86_64_INTEGERSI_CLASS;
     192           0 :             return 2;
     193             :           }
     194             :         else
     195           0 :           FFI_ASSERT (0);
     196             :       }
     197             :     case FFI_TYPE_FLOAT:
     198           0 :       if (!(byte_offset % 8))
     199           0 :         classes[0] = X86_64_SSESF_CLASS;
     200             :       else
     201           0 :         classes[0] = X86_64_SSE_CLASS;
     202           0 :       return 1;
     203             :     case FFI_TYPE_DOUBLE:
     204           0 :       classes[0] = X86_64_SSEDF_CLASS;
     205           0 :       return 1;
     206             : #if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
     207             :     case FFI_TYPE_LONGDOUBLE:
     208             :       classes[0] = X86_64_X87_CLASS;
     209             :       classes[1] = X86_64_X87UP_CLASS;
     210             :       return 2;
     211             : #endif
     212             :     case FFI_TYPE_STRUCT:
     213             :       {
     214           0 :         const size_t UNITS_PER_WORD = 8;
     215           0 :         size_t words = (type->size + UNITS_PER_WORD - 1) / UNITS_PER_WORD;
     216             :         ffi_type **ptr;
     217             :         int i;
     218             :         enum x86_64_reg_class subclasses[MAX_CLASSES];
     219             : 
     220             :         /* If the struct is larger than 32 bytes, pass it on the stack.  */
     221           0 :         if (type->size > 32)
     222           0 :           return 0;
     223             : 
     224           0 :         for (i = 0; i < words; i++)
     225           0 :           classes[i] = X86_64_NO_CLASS;
     226             : 
     227             :         /* Zero sized arrays or structures are NO_CLASS.  We return 0 to
     228             :            signalize memory class, so handle it as special case.  */
     229           0 :         if (!words)
     230             :           {
     231           0 :             classes[0] = X86_64_NO_CLASS;
     232           0 :             return 1;
     233             :           }
     234             : 
     235             :         /* Merge the fields of structure.  */
     236           0 :         for (ptr = type->elements; *ptr != NULL; ptr++)
     237             :           {
     238             :             size_t num;
     239             : 
     240           0 :             byte_offset = ALIGN (byte_offset, (*ptr)->alignment);
     241             : 
     242           0 :             num = classify_argument (*ptr, subclasses, byte_offset % 8);
     243           0 :             if (num == 0)
     244           0 :               return 0;
     245           0 :             for (i = 0; i < num; i++)
     246             :               {
     247           0 :                 size_t pos = byte_offset / 8;
     248           0 :                 classes[i + pos] =
     249           0 :                   merge_classes (subclasses[i], classes[i + pos]);
     250             :               }
     251             : 
     252           0 :             byte_offset += (*ptr)->size;
     253             :           }
     254             : 
     255           0 :         if (words > 2)
     256             :           {
     257             :             /* When size > 16 bytes, if the first one isn't
     258             :                X86_64_SSE_CLASS or any other ones aren't
     259             :                X86_64_SSEUP_CLASS, everything should be passed in
     260             :                memory.  */
     261           0 :             if (classes[0] != X86_64_SSE_CLASS)
     262           0 :               return 0;
     263             : 
     264           0 :             for (i = 1; i < words; i++)
     265           0 :               if (classes[i] != X86_64_SSEUP_CLASS)
     266           0 :                 return 0;
     267             :           }
     268             : 
     269             :         /* Final merger cleanup.  */
     270           0 :         for (i = 0; i < words; i++)
     271             :           {
     272             :             /* If one class is MEMORY, everything should be passed in
     273             :                memory.  */
     274           0 :             if (classes[i] == X86_64_MEMORY_CLASS)
     275           0 :               return 0;
     276             : 
     277             :             /* The X86_64_SSEUP_CLASS should be always preceded by
     278             :                X86_64_SSE_CLASS or X86_64_SSEUP_CLASS.  */
     279           0 :             if (classes[i] == X86_64_SSEUP_CLASS
     280           0 :                 && classes[i - 1] != X86_64_SSE_CLASS
     281           0 :                 && classes[i - 1] != X86_64_SSEUP_CLASS)
     282             :               {
     283             :                 /* The first one should never be X86_64_SSEUP_CLASS.  */
     284           0 :                 FFI_ASSERT (i != 0);
     285           0 :                 classes[i] = X86_64_SSE_CLASS;
     286             :               }
     287             : 
     288             :             /*  If X86_64_X87UP_CLASS isn't preceded by X86_64_X87_CLASS,
     289             :                 everything should be passed in memory.  */
     290           0 :             if (classes[i] == X86_64_X87UP_CLASS
     291           0 :                 && (classes[i - 1] != X86_64_X87_CLASS))
     292             :               {
     293             :                 /* The first one should never be X86_64_X87UP_CLASS.  */
     294           0 :                 FFI_ASSERT (i != 0);
     295           0 :                 return 0;
     296             :               }
     297             :           }
     298           0 :         return words;
     299             :       }
     300             : 
     301             :     default:
     302           0 :       FFI_ASSERT(0);
     303             :     }
     304           0 :   return 0; /* Never reached.  */
     305             : }
     306             : 
     307             : /* Examine the argument and return set number of register required in each
     308             :    class.  Return zero iff parameter should be passed in memory, otherwise
     309             :    the number of registers.  */
     310             : 
     311             : static size_t
     312           0 : examine_argument (ffi_type *type, enum x86_64_reg_class classes[MAX_CLASSES],
     313             :                   _Bool in_return, int *pngpr, int *pnsse)
     314             : {
     315             :   size_t n;
     316             :   int i, ngpr, nsse;
     317             : 
     318           0 :   n = classify_argument (type, classes, 0);
     319           0 :   if (n == 0)
     320           0 :     return 0;
     321             : 
     322           0 :   ngpr = nsse = 0;
     323           0 :   for (i = 0; i < n; ++i)
     324           0 :     switch (classes[i])
     325             :       {
     326             :       case X86_64_INTEGER_CLASS:
     327             :       case X86_64_INTEGERSI_CLASS:
     328           0 :         ngpr++;
     329           0 :         break;
     330             :       case X86_64_SSE_CLASS:
     331             :       case X86_64_SSESF_CLASS:
     332             :       case X86_64_SSEDF_CLASS:
     333           0 :         nsse++;
     334           0 :         break;
     335             :       case X86_64_NO_CLASS:
     336             :       case X86_64_SSEUP_CLASS:
     337           0 :         break;
     338             :       case X86_64_X87_CLASS:
     339             :       case X86_64_X87UP_CLASS:
     340             :       case X86_64_COMPLEX_X87_CLASS:
     341           0 :         return in_return != 0;
     342             :       default:
     343           0 :         abort ();
     344             :       }
     345             : 
     346           0 :   *pngpr = ngpr;
     347           0 :   *pnsse = nsse;
     348             : 
     349           0 :   return n;
     350             : }
     351             : 
     352             : /* Perform machine dependent cif processing.  */
     353             : 
     354             : ffi_status
     355           0 : ffi_prep_cif_machdep (ffi_cif *cif)
     356             : {
     357             :   int gprcount, ssecount, i, avn, ngpr, nsse, flags;
     358             :   enum x86_64_reg_class classes[MAX_CLASSES];
     359             :   size_t bytes, n;
     360             : 
     361           0 :   gprcount = ssecount = 0;
     362             : 
     363           0 :   flags = cif->rtype->type;
     364           0 :   if (flags != FFI_TYPE_VOID)
     365             :     {
     366           0 :       n = examine_argument (cif->rtype, classes, 1, &ngpr, &nsse);
     367           0 :       if (n == 0)
     368             :         {
     369             :           /* The return value is passed in memory.  A pointer to that
     370             :              memory is the first argument.  Allocate a register for it.  */
     371           0 :           gprcount++;
     372             :           /* We don't have to do anything in asm for the return.  */
     373           0 :           flags = FFI_TYPE_VOID;
     374             :         }
     375           0 :       else if (flags == FFI_TYPE_STRUCT)
     376             :         {
     377             :           /* Mark which registers the result appears in.  */
     378           0 :           _Bool sse0 = SSE_CLASS_P (classes[0]);
     379           0 :           _Bool sse1 = n == 2 && SSE_CLASS_P (classes[1]);
     380           0 :           if (sse0 && !sse1)
     381           0 :             flags |= 1 << 8;
     382           0 :           else if (!sse0 && sse1)
     383           0 :             flags |= 1 << 9;
     384           0 :           else if (sse0 && sse1)
     385           0 :             flags |= 1 << 10;
     386             :           /* Mark the true size of the structure.  */
     387           0 :           flags |= cif->rtype->size << 12;
     388             :         }
     389             :     }
     390             : 
     391             :   /* Go over all arguments and determine the way they should be passed.
     392             :      If it's in a register and there is space for it, let that be so. If
     393             :      not, add it's size to the stack byte count.  */
     394           0 :   for (bytes = 0, i = 0, avn = cif->nargs; i < avn; i++)
     395             :     {
     396           0 :       if (examine_argument (cif->arg_types[i], classes, 0, &ngpr, &nsse) == 0
     397           0 :           || gprcount + ngpr > MAX_GPR_REGS
     398           0 :           || ssecount + nsse > MAX_SSE_REGS)
     399           0 :         {
     400           0 :           long align = cif->arg_types[i]->alignment;
     401             : 
     402           0 :           if (align < 8)
     403           0 :             align = 8;
     404             : 
     405           0 :           bytes = ALIGN (bytes, align);
     406           0 :           bytes += cif->arg_types[i]->size;
     407             :         }
     408             :       else
     409             :         {
     410           0 :           gprcount += ngpr;
     411           0 :           ssecount += nsse;
     412             :         }
     413             :     }
     414           0 :   if (ssecount)
     415           0 :     flags |= 1 << 11;
     416           0 :   cif->flags = flags;
     417           0 :   cif->bytes = (unsigned)ALIGN (bytes, 8);
     418             : 
     419           0 :   return FFI_OK;
     420             : }
     421             : 
     422             : #ifndef __SANITIZE_ADDRESS__
     423             : # ifdef __clang__
     424             : #  if __has_feature(address_sanitizer)
     425             : #   define __SANITIZE_ADDRESS__
     426             : #  endif
     427             : # endif
     428             : #endif
     429             : #ifdef __SANITIZE_ADDRESS__
     430             : __attribute__((noinline,no_sanitize_address))
     431             : #endif
     432             : void
     433           0 : ffi_call (ffi_cif *cif, void (*fn)(void), void *rvalue, void **avalue)
     434             : {
     435             :   enum x86_64_reg_class classes[MAX_CLASSES];
     436             :   char *stack, *argp;
     437             :   ffi_type **arg_types;
     438             :   int gprcount, ssecount, ngpr, nsse, i, avn;
     439             :   _Bool ret_in_memory;
     440             :   struct register_args *reg_args;
     441             : 
     442             :   /* Can't call 32-bit mode from 64-bit mode.  */
     443           0 :   FFI_ASSERT (cif->abi == FFI_UNIX64);
     444             : 
     445             :   /* If the return value is a struct and we don't have a return value
     446             :      address then we need to make one.  Note the setting of flags to
     447             :      VOID above in ffi_prep_cif_machdep.  */
     448           0 :   ret_in_memory = (cif->rtype->type == FFI_TYPE_STRUCT
     449           0 :                    && (cif->flags & 0xff) == FFI_TYPE_VOID);
     450           0 :   if (rvalue == NULL && ret_in_memory)
     451           0 :     rvalue = alloca (cif->rtype->size);
     452             : 
     453             :   /* Allocate the space for the arguments, plus 4 words of temp space.  */
     454           0 :   stack = alloca (sizeof (struct register_args) + cif->bytes + 4*8);
     455           0 :   reg_args = (struct register_args *) stack;
     456           0 :   argp = stack + sizeof (struct register_args);
     457             : 
     458           0 :   gprcount = ssecount = 0;
     459             : 
     460             :   /* If the return value is passed in memory, add the pointer as the
     461             :      first integer argument.  */
     462           0 :   if (ret_in_memory)
     463           0 :     reg_args->gpr[gprcount++] = (unsigned long) rvalue;
     464             : 
     465           0 :   avn = cif->nargs;
     466           0 :   arg_types = cif->arg_types;
     467             : 
     468           0 :   for (i = 0; i < avn; ++i)
     469             :     {
     470           0 :       size_t n, size = arg_types[i]->size;
     471             : 
     472           0 :       n = examine_argument (arg_types[i], classes, 0, &ngpr, &nsse);
     473           0 :       if (n == 0
     474           0 :           || gprcount + ngpr > MAX_GPR_REGS
     475           0 :           || ssecount + nsse > MAX_SSE_REGS)
     476           0 :         {
     477           0 :           long align = arg_types[i]->alignment;
     478             : 
     479             :           /* Stack arguments are *always* at least 8 byte aligned.  */
     480           0 :           if (align < 8)
     481           0 :             align = 8;
     482             : 
     483             :           /* Pass this argument in memory.  */
     484           0 :           argp = (void *) ALIGN (argp, align);
     485           0 :           memcpy (argp, avalue[i], size);
     486           0 :           argp += size;
     487             :         }
     488             :       else
     489             :         {
     490             :           /* The argument is passed entirely in registers.  */
     491           0 :           char *a = (char *) avalue[i];
     492             :           int j;
     493             : 
     494           0 :           for (j = 0; j < n; j++, a += 8, size -= 8)
     495             :             {
     496           0 :               switch (classes[j])
     497             :                 {
     498             :                 case X86_64_INTEGER_CLASS:
     499             :                 case X86_64_INTEGERSI_CLASS:
     500             :                   /* Sign-extend integer arguments passed in general
     501             :                      purpose registers, to cope with the fact that
     502             :                      LLVM incorrectly assumes that this will be done
     503             :                      (the x86-64 PS ABI does not specify this). */
     504           0 :                   switch (arg_types[i]->type)
     505             :                     {
     506             :                     case FFI_TYPE_SINT8:
     507           0 :                       *(SINT64 *)&reg_args->gpr[gprcount] = (SINT64) *((SINT8 *) a);
     508           0 :                       break;
     509             :                     case FFI_TYPE_SINT16:
     510           0 :                       *(SINT64 *)&reg_args->gpr[gprcount] = (SINT64) *((SINT16 *) a);
     511           0 :                       break;
     512             :                     case FFI_TYPE_SINT32:
     513           0 :                       *(SINT64 *)&reg_args->gpr[gprcount] = (SINT64) *((SINT32 *) a);
     514           0 :                       break;
     515             :                     default:
     516           0 :                       reg_args->gpr[gprcount] = 0;
     517           0 :                       memcpy (&reg_args->gpr[gprcount], a, size < 8 ? size : 8);
     518             :                     }
     519           0 :                   gprcount++;
     520           0 :                   break;
     521             :                 case X86_64_SSE_CLASS:
     522             :                 case X86_64_SSEDF_CLASS:
     523           0 :                   reg_args->sse[ssecount++].i64 = *(UINT64 *) a;
     524           0 :                   break;
     525             :                 case X86_64_SSESF_CLASS:
     526           0 :                   reg_args->sse[ssecount++].i32 = *(UINT32 *) a;
     527           0 :                   break;
     528             :                 default:
     529           0 :                   abort();
     530             :                 }
     531             :             }
     532             :         }
     533             :     }
     534             : 
     535           0 :   ffi_call_unix64 (stack, cif->bytes + sizeof (struct register_args),
     536             :                    cif->flags, rvalue, fn, ssecount);
     537           0 : }
     538             : 
     539             : 
     540             : extern void ffi_closure_unix64(void);
     541             : 
     542             : ffi_status
     543           0 : ffi_prep_closure_loc (ffi_closure* closure,
     544             :                       ffi_cif* cif,
     545             :                       void (*fun)(ffi_cif*, void*, void**, void*),
     546             :                       void *user_data,
     547             :                       void *codeloc)
     548             : {
     549             :   volatile unsigned short *tramp;
     550             : 
     551             :   /* Sanity check on the cif ABI.  */
     552             :   {
     553           0 :     int abi = cif->abi;
     554           0 :     if (UNLIKELY (! (abi > FFI_FIRST_ABI && abi < FFI_LAST_ABI)))
     555           0 :       return FFI_BAD_ABI;
     556             :   }
     557             : 
     558           0 :   tramp = (volatile unsigned short *) &closure->tramp[0];
     559             : 
     560           0 :   tramp[0] = 0xbb49;            /* mov <code>, %r11       */
     561           0 :   *((unsigned long long * volatile) &tramp[1])
     562           0 :     = (unsigned long) ffi_closure_unix64;
     563           0 :   tramp[5] = 0xba49;            /* mov <data>, %r10       */
     564           0 :   *((unsigned long long * volatile) &tramp[6])
     565           0 :     = (unsigned long) codeloc;
     566             : 
     567             :   /* Set the carry bit iff the function uses any sse registers.
     568             :      This is clc or stc, together with the first byte of the jmp.  */
     569           0 :   tramp[10] = cif->flags & (1 << 11) ? 0x49f9 : 0x49f8;
     570             : 
     571           0 :   tramp[11] = 0xe3ff;                   /* jmp *%r11    */
     572             : 
     573           0 :   closure->cif = cif;
     574           0 :   closure->fun = fun;
     575           0 :   closure->user_data = user_data;
     576             : 
     577           0 :   return FFI_OK;
     578             : }
     579             : 
     580             : int
     581           0 : ffi_closure_unix64_inner(ffi_closure *closure, void *rvalue,
     582             :                          struct register_args *reg_args, char *argp)
     583             : {
     584             :   ffi_cif *cif;
     585             :   void **avalue;
     586             :   ffi_type **arg_types;
     587             :   long i, avn;
     588             :   int gprcount, ssecount, ngpr, nsse;
     589             :   int ret;
     590             : 
     591           0 :   cif = closure->cif;
     592           0 :   avalue = alloca(cif->nargs * sizeof(void *));
     593           0 :   gprcount = ssecount = 0;
     594             : 
     595           0 :   ret = cif->rtype->type;
     596           0 :   if (ret != FFI_TYPE_VOID)
     597             :     {
     598             :       enum x86_64_reg_class classes[MAX_CLASSES];
     599           0 :       size_t n = examine_argument (cif->rtype, classes, 1, &ngpr, &nsse);
     600           0 :       if (n == 0)
     601             :         {
     602             :           /* The return value goes in memory.  Arrange for the closure
     603             :              return value to go directly back to the original caller.  */
     604           0 :           rvalue = (void *) (unsigned long) reg_args->gpr[gprcount++];
     605             :           /* We don't have to do anything in asm for the return.  */
     606           0 :           ret = FFI_TYPE_VOID;
     607             :         }
     608           0 :       else if (ret == FFI_TYPE_STRUCT && n == 2)
     609             :         {
     610             :           /* Mark which register the second word of the structure goes in.  */
     611           0 :           _Bool sse0 = SSE_CLASS_P (classes[0]);
     612           0 :           _Bool sse1 = SSE_CLASS_P (classes[1]);
     613           0 :           if (!sse0 && sse1)
     614           0 :             ret |= 1 << 8;
     615           0 :           else if (sse0 && !sse1)
     616           0 :             ret |= 1 << 9;
     617             :         }
     618             :     }
     619             : 
     620           0 :   avn = cif->nargs;
     621           0 :   arg_types = cif->arg_types;
     622             : 
     623           0 :   for (i = 0; i < avn; ++i)
     624             :     {
     625             :       enum x86_64_reg_class classes[MAX_CLASSES];
     626             :       size_t n;
     627             : 
     628           0 :       n = examine_argument (arg_types[i], classes, 0, &ngpr, &nsse);
     629           0 :       if (n == 0
     630           0 :           || gprcount + ngpr > MAX_GPR_REGS
     631           0 :           || ssecount + nsse > MAX_SSE_REGS)
     632           0 :         {
     633           0 :           long align = arg_types[i]->alignment;
     634             : 
     635             :           /* Stack arguments are *always* at least 8 byte aligned.  */
     636           0 :           if (align < 8)
     637           0 :             align = 8;
     638             : 
     639             :           /* Pass this argument in memory.  */
     640           0 :           argp = (void *) ALIGN (argp, align);
     641           0 :           avalue[i] = argp;
     642           0 :           argp += arg_types[i]->size;
     643             :         }
     644             :       /* If the argument is in a single register, or two consecutive
     645             :          integer registers, then we can use that address directly.  */
     646           0 :       else if (n == 1
     647           0 :                || (n == 2 && !(SSE_CLASS_P (classes[0])
     648           0 :                                || SSE_CLASS_P (classes[1]))))
     649             :         {
     650             :           /* The argument is in a single register.  */
     651           0 :           if (SSE_CLASS_P (classes[0]))
     652             :             {
     653           0 :               avalue[i] = &reg_args->sse[ssecount];
     654           0 :               ssecount += n;
     655             :             }
     656             :           else
     657             :             {
     658           0 :               avalue[i] = &reg_args->gpr[gprcount];
     659           0 :               gprcount += n;
     660             :             }
     661             :         }
     662             :       /* Otherwise, allocate space to make them consecutive.  */
     663             :       else
     664             :         {
     665           0 :           char *a = alloca (16);
     666             :           int j;
     667             : 
     668           0 :           avalue[i] = a;
     669           0 :           for (j = 0; j < n; j++, a += 8)
     670             :             {
     671           0 :               if (SSE_CLASS_P (classes[j]))
     672           0 :                 memcpy (a, &reg_args->sse[ssecount++], 8);
     673             :               else
     674           0 :                 memcpy (a, &reg_args->gpr[gprcount++], 8);
     675             :             }
     676             :         }
     677             :     }
     678             : 
     679             :   /* Invoke the closure.  */
     680           0 :   closure->fun (cif, rvalue, avalue, closure->user_data);
     681             : 
     682             :   /* Tell assembly how to perform return type promotions.  */
     683           0 :   return ret;
     684             : }
     685             : 
     686             : #endif /* __x86_64__ */

Generated by: LCOV version 1.13