< prev index next >

modules/javafx.media/src/main/native/gstreamer/3rd_party/libffi/src/x86/ffi64.c

Print this page
@@ -1,8 +1,8 @@
  /* -----------------------------------------------------------------------
-    ffi64.c - Copyright (c) 2013  The Written Word, Inc.
-              Copyright (c) 2011  Anthony Green
+    ffi64.c - Copyright (c) 2011, 2018  Anthony Green
+              Copyright (c) 2013  The Written Word, Inc.
               Copyright (c) 2008, 2010  Red Hat, Inc.
               Copyright (c) 2002, 2007  Bo Thorsen <bo@suse.de>
  
     x86-64 Foreign Function Interface
  

@@ -30,10 +30,12 @@
  #include <ffi.h>
  #include <ffi_common.h>
  
  #include <stdlib.h>
  #include <stdarg.h>
+ #include <stdint.h>
+ #include "internal64.h"
  
  #ifdef __x86_64__
  
  #define MAX_GPR_REGS 6
  #define MAX_SSE_REGS 8

@@ -60,14 +62,16 @@
  struct register_args
  {
    /* Registers for argument passing.  */
    UINT64 gpr[MAX_GPR_REGS];
    union big_int_union sse[MAX_SSE_REGS];
+   UINT64 rax;   /* ssecount */
+   UINT64 r10;   /* static chain */
  };
  
  extern void ffi_call_unix64 (void *args, unsigned long bytes, unsigned flags,
-                  void *raddr, void (*fnaddr)(void), unsigned ssecount);
+                  void *raddr, void (*fnaddr)(void)) FFI_HIDDEN;
  
  /* All reference to register classes here is identical to the code in
     gcc/config/i386/i386.c. Do *not* change one without the other.  */
  
  /* Register class used for passing given 64bit part of the argument.

@@ -165,10 +169,11 @@
      case FFI_TYPE_UINT32:
      case FFI_TYPE_SINT32:
      case FFI_TYPE_UINT64:
      case FFI_TYPE_SINT64:
      case FFI_TYPE_POINTER:
+     do_integer:
        {
      size_t size = byte_offset + type->size;
  
      if (size <= 4)
        {

@@ -186,11 +191,11 @@
          classes[1] = X86_64_INTEGERSI_CLASS;
          return 2;
        }
      else if (size <= 16)
        {
-         classes[0] = classes[1] = X86_64_INTEGERSI_CLASS;
+         classes[0] = classes[1] = X86_64_INTEGER_CLASS;
          return 2;
        }
      else
        FFI_ASSERT (0);
        }

@@ -212,11 +217,11 @@
      case FFI_TYPE_STRUCT:
        {
      const size_t UNITS_PER_WORD = 8;
      size_t words = (type->size + UNITS_PER_WORD - 1) / UNITS_PER_WORD;
      ffi_type **ptr;
-     int i;
+     unsigned int i;
      enum x86_64_reg_class subclasses[MAX_CLASSES];
  
      /* If the struct is larger than 32 bytes, pass it on the stack.  */
      if (type->size > 32)
        return 0;

@@ -226,20 +231,21 @@
  
      /* Zero sized arrays or structures are NO_CLASS.  We return 0 to
         signalize memory class, so handle it as special case.  */
      if (!words)
        {
+     case FFI_TYPE_VOID:
          classes[0] = X86_64_NO_CLASS;
          return 1;
        }
  
      /* Merge the fields of structure.  */
      for (ptr = type->elements; *ptr != NULL; ptr++)
        {
          size_t num;
  
-         byte_offset = ALIGN (byte_offset, (*ptr)->alignment);
+         byte_offset = FFI_ALIGN (byte_offset, (*ptr)->alignment);
  
          num = classify_argument (*ptr, subclasses, byte_offset % 8);
          if (num == 0)
            return 0;
          for (i = 0; i < num; i++)

@@ -274,36 +280,67 @@
          if (classes[i] == X86_64_MEMORY_CLASS)
            return 0;
  
          /* The X86_64_SSEUP_CLASS should be always preceded by
             X86_64_SSE_CLASS or X86_64_SSEUP_CLASS.  */
-         if (classes[i] == X86_64_SSEUP_CLASS
+         if (i > 1 && classes[i] == X86_64_SSEUP_CLASS
          && classes[i - 1] != X86_64_SSE_CLASS
          && classes[i - 1] != X86_64_SSEUP_CLASS)
            {
          /* The first one should never be X86_64_SSEUP_CLASS.  */
          FFI_ASSERT (i != 0);
          classes[i] = X86_64_SSE_CLASS;
            }
  
          /*  If X86_64_X87UP_CLASS isn't preceded by X86_64_X87_CLASS,
          everything should be passed in memory.  */
-         if (classes[i] == X86_64_X87UP_CLASS
+         if (i > 1 && classes[i] == X86_64_X87UP_CLASS
          && (classes[i - 1] != X86_64_X87_CLASS))
            {
          /* The first one should never be X86_64_X87UP_CLASS.  */
          FFI_ASSERT (i != 0);
          return 0;
            }
        }
      return words;
        }
- 
-     default:
-       FFI_ASSERT(0);
+     case FFI_TYPE_COMPLEX:
+       {
+     ffi_type *inner = type->elements[0];
+     switch (inner->type)
+       {
+       case FFI_TYPE_INT:
+       case FFI_TYPE_UINT8:
+       case FFI_TYPE_SINT8:
+       case FFI_TYPE_UINT16:
+       case FFI_TYPE_SINT16:
+       case FFI_TYPE_UINT32:
+       case FFI_TYPE_SINT32:
+       case FFI_TYPE_UINT64:
+       case FFI_TYPE_SINT64:
+         goto do_integer;
+ 
+       case FFI_TYPE_FLOAT:
+         classes[0] = X86_64_SSE_CLASS;
+         if (byte_offset % 8)
+           {
+         classes[1] = X86_64_SSESF_CLASS;
+         return 2;
      }
-   return 0; /* Never reached.  */
+         return 1;
+       case FFI_TYPE_DOUBLE:
+         classes[0] = classes[1] = X86_64_SSEDF_CLASS;
+         return 2;
+ #if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
+       case FFI_TYPE_LONGDOUBLE:
+         classes[0] = X86_64_COMPLEX_X87_CLASS;
+         return 1;
+ #endif
+ }
+       }
+     }
+   abort();
  }
  
  /* Examine the argument and return set number of register required in each
     class.  Return zero iff parameter should be passed in memory, otherwise
     the number of registers.  */

@@ -311,11 +348,12 @@
  static size_t
  examine_argument (ffi_type *type, enum x86_64_reg_class classes[MAX_CLASSES],
            _Bool in_return, int *pngpr, int *pnsse)
  {
    size_t n;
-   int i, ngpr, nsse;
+   unsigned int i;
+   int ngpr, nsse;
  
    n = classify_argument (type, classes, 0);
    if (n == 0)
      return 0;
  

@@ -349,46 +387,142 @@
    return n;
  }
  
  /* Perform machine dependent cif processing.  */
  
- ffi_status
+ #ifndef __ILP32__
+ extern ffi_status
+ ffi_prep_cif_machdep_efi64(ffi_cif *cif);
+ #endif
+ 
+ ffi_status FFI_HIDDEN
  ffi_prep_cif_machdep (ffi_cif *cif)
  {
-   int gprcount, ssecount, i, avn, ngpr, nsse, flags;
+   int gprcount, ssecount, i, avn, ngpr, nsse;
+   unsigned flags;
    enum x86_64_reg_class classes[MAX_CLASSES];
-   size_t bytes, n;
+   size_t bytes, n, rtype_size;
+   ffi_type *rtype;
+ 
+ #ifndef __ILP32__
+   if (cif->abi == FFI_EFI64 || cif->abi == FFI_GNUW64)
+     return ffi_prep_cif_machdep_efi64(cif);
+ #endif
+   if (cif->abi != FFI_UNIX64)
+     return FFI_BAD_ABI;
  
    gprcount = ssecount = 0;
  
-   flags = cif->rtype->type;
-   if (flags != FFI_TYPE_VOID)
+   rtype = cif->rtype;
+   rtype_size = rtype->size;
+   switch (rtype->type)
      {
+     case FFI_TYPE_VOID:
+       flags = UNIX64_RET_VOID;
+       break;
+     case FFI_TYPE_UINT8:
+       flags = UNIX64_RET_UINT8;
+       break;
+     case FFI_TYPE_SINT8:
+       flags = UNIX64_RET_SINT8;
+       break;
+     case FFI_TYPE_UINT16:
+       flags = UNIX64_RET_UINT16;
+       break;
+     case FFI_TYPE_SINT16:
+       flags = UNIX64_RET_SINT16;
+       break;
+     case FFI_TYPE_UINT32:
+       flags = UNIX64_RET_UINT32;
+       break;
+     case FFI_TYPE_INT:
+     case FFI_TYPE_SINT32:
+       flags = UNIX64_RET_SINT32;
+       break;
+     case FFI_TYPE_UINT64:
+     case FFI_TYPE_SINT64:
+       flags = UNIX64_RET_INT64;
+       break;
+     case FFI_TYPE_POINTER:
+       flags = (sizeof(void *) == 4 ? UNIX64_RET_UINT32 : UNIX64_RET_INT64);
+       break;
+     case FFI_TYPE_FLOAT:
+       flags = UNIX64_RET_XMM32;
+       break;
+     case FFI_TYPE_DOUBLE:
+       flags = UNIX64_RET_XMM64;
+       break;
+ #if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
+     case FFI_TYPE_LONGDOUBLE:
+       flags = UNIX64_RET_X87;
+       break;
+ #endif
+     case FFI_TYPE_STRUCT:
        n = examine_argument (cif->rtype, classes, 1, &ngpr, &nsse);
        if (n == 0)
      {
        /* The return value is passed in memory.  A pointer to that
           memory is the first argument.  Allocate a register for it.  */
        gprcount++;
        /* We don't have to do anything in asm for the return.  */
-       flags = FFI_TYPE_VOID;
+       flags = UNIX64_RET_VOID | UNIX64_FLAG_RET_IN_MEM;
      }
-       else if (flags == FFI_TYPE_STRUCT)
+       else
      {
-       /* Mark which registers the result appears in.  */
        _Bool sse0 = SSE_CLASS_P (classes[0]);
+ 
+       if (rtype_size == 4 && sse0)
+         flags = UNIX64_RET_XMM32;
+       else if (rtype_size == 8)
+         flags = sse0 ? UNIX64_RET_XMM64 : UNIX64_RET_INT64;
+       else
+         {
        _Bool sse1 = n == 2 && SSE_CLASS_P (classes[1]);
-       if (sse0 && !sse1)
-         flags |= 1 << 8;
-       else if (!sse0 && sse1)
-         flags |= 1 << 9;
-       else if (sse0 && sse1)
-         flags |= 1 << 10;
-       /* Mark the true size of the structure.  */
-       flags |= cif->rtype->size << 12;
+           if (sse0 && sse1)
+         flags = UNIX64_RET_ST_XMM0_XMM1;
+           else if (sse0)
+         flags = UNIX64_RET_ST_XMM0_RAX;
+           else if (sse1)
+         flags = UNIX64_RET_ST_RAX_XMM0;
+           else
+         flags = UNIX64_RET_ST_RAX_RDX;
+           flags |= rtype_size << UNIX64_SIZE_SHIFT;
      }
      }
+       break;
+     case FFI_TYPE_COMPLEX:
+       switch (rtype->elements[0]->type)
+     {
+     case FFI_TYPE_UINT8:
+     case FFI_TYPE_SINT8:
+     case FFI_TYPE_UINT16:
+     case FFI_TYPE_SINT16:
+     case FFI_TYPE_INT:
+     case FFI_TYPE_UINT32:
+     case FFI_TYPE_SINT32:
+     case FFI_TYPE_UINT64:
+     case FFI_TYPE_SINT64:
+       flags = UNIX64_RET_ST_RAX_RDX | ((unsigned) rtype_size << UNIX64_SIZE_SHIFT);
+       break;
+     case FFI_TYPE_FLOAT:
+       flags = UNIX64_RET_XMM64;
+       break;
+     case FFI_TYPE_DOUBLE:
+       flags = UNIX64_RET_ST_XMM0_XMM1 | (16 << UNIX64_SIZE_SHIFT);
+       break;
+ #if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
+     case FFI_TYPE_LONGDOUBLE:
+       flags = UNIX64_RET_X87_2;
+       break;
+ #endif
+     default:
+       return FFI_BAD_TYPEDEF;
+     }
+       break;
+     default:
+       return FFI_BAD_TYPEDEF;
+     }
  
    /* Go over all arguments and determine the way they should be passed.
       If it's in a register and there is space for it, let that be so. If
       not, add it's size to the stack byte count.  */
    for (bytes = 0, i = 0, avn = cif->nargs; i < avn; i++)

@@ -400,58 +534,64 @@
        long align = cif->arg_types[i]->alignment;
  
        if (align < 8)
          align = 8;
  
-       bytes = ALIGN (bytes, align);
+       bytes = FFI_ALIGN (bytes, align);
        bytes += cif->arg_types[i]->size;
      }
        else
      {
        gprcount += ngpr;
        ssecount += nsse;
      }
      }
    if (ssecount)
-     flags |= 1 << 11;
+     flags |= UNIX64_FLAG_XMM_ARGS;
+ 
    cif->flags = flags;
-   cif->bytes = (unsigned)ALIGN (bytes, 8);
+   cif->bytes = (unsigned) FFI_ALIGN (bytes, 8);
  
    return FFI_OK;
  }
  
- void
- ffi_call (ffi_cif *cif, void (*fn)(void), void *rvalue, void **avalue)
+ static void
+ ffi_call_int (ffi_cif *cif, void (*fn)(void), void *rvalue,
+           void **avalue, void *closure)
  {
    enum x86_64_reg_class classes[MAX_CLASSES];
    char *stack, *argp;
    ffi_type **arg_types;
-   int gprcount, ssecount, ngpr, nsse, i, avn;
-   _Bool ret_in_memory;
+   int gprcount, ssecount, ngpr, nsse, i, avn, flags;
    struct register_args *reg_args;
  
    /* Can't call 32-bit mode from 64-bit mode.  */
    FFI_ASSERT (cif->abi == FFI_UNIX64);
  
    /* If the return value is a struct and we don't have a return value
-      address then we need to make one.  Note the setting of flags to
-      VOID above in ffi_prep_cif_machdep.  */
-   ret_in_memory = (cif->rtype->type == FFI_TYPE_STRUCT
-            && (cif->flags & 0xff) == FFI_TYPE_VOID);
-   if (rvalue == NULL && ret_in_memory)
+      address then we need to make one.  Otherwise we can ignore it.  */
+   flags = cif->flags;
+   if (rvalue == NULL)
+     {
+       if (flags & UNIX64_FLAG_RET_IN_MEM)
      rvalue = alloca (cif->rtype->size);
+       else
+     flags = UNIX64_RET_VOID;
+     }
  
    /* Allocate the space for the arguments, plus 4 words of temp space.  */
    stack = alloca (sizeof (struct register_args) + cif->bytes + 4*8);
    reg_args = (struct register_args *) stack;
    argp = stack + sizeof (struct register_args);
  
+   reg_args->r10 = (uintptr_t) closure;
+ 
    gprcount = ssecount = 0;
  
    /* If the return value is passed in memory, add the pointer as the
       first integer argument.  */
-   if (ret_in_memory)
+   if (flags & UNIX64_FLAG_RET_IN_MEM)
      reg_args->gpr[gprcount++] = (unsigned long) rvalue;
  
    avn = cif->nargs;
    arg_types = cif->arg_types;
  

@@ -469,149 +609,190 @@
        /* Stack arguments are *always* at least 8 byte aligned.  */
        if (align < 8)
          align = 8;
  
        /* Pass this argument in memory.  */
-       argp = (void *) ALIGN (argp, align);
+       argp = (void *) FFI_ALIGN (argp, align);
        memcpy (argp, avalue[i], size);
        argp += size;
      }
        else
      {
        /* The argument is passed entirely in registers.  */
        char *a = (char *) avalue[i];
-       int j;
+       unsigned int j;
  
        for (j = 0; j < n; j++, a += 8, size -= 8)
          {
            switch (classes[j])
          {
+         case X86_64_NO_CLASS:
+         case X86_64_SSEUP_CLASS:
+           break;
          case X86_64_INTEGER_CLASS:
          case X86_64_INTEGERSI_CLASS:
            /* Sign-extend integer arguments passed in general
               purpose registers, to cope with the fact that
               LLVM incorrectly assumes that this will be done
               (the x86-64 PS ABI does not specify this). */
            switch (arg_types[i]->type)
              {
              case FFI_TYPE_SINT8:
-               *(SINT64 *)&reg_args->gpr[gprcount] = (SINT64) *((SINT8 *) a);
+               reg_args->gpr[gprcount] = (SINT64) *((SINT8 *) a);
                break;
              case FFI_TYPE_SINT16:
-               *(SINT64 *)&reg_args->gpr[gprcount] = (SINT64) *((SINT16 *) a);
+               reg_args->gpr[gprcount] = (SINT64) *((SINT16 *) a);
                break;
              case FFI_TYPE_SINT32:
-               *(SINT64 *)&reg_args->gpr[gprcount] = (SINT64) *((SINT32 *) a);
+               reg_args->gpr[gprcount] = (SINT64) *((SINT32 *) a);
                break;
              default:
                reg_args->gpr[gprcount] = 0;
-               memcpy (&reg_args->gpr[gprcount], a, size < 8 ? size : 8);
+               memcpy (&reg_args->gpr[gprcount], a, size);
              }
            gprcount++;
            break;
          case X86_64_SSE_CLASS:
          case X86_64_SSEDF_CLASS:
-           reg_args->sse[ssecount++].i64 = *(UINT64 *) a;
+           memcpy (&reg_args->sse[ssecount++].i64, a, sizeof(UINT64));
            break;
          case X86_64_SSESF_CLASS:
-           reg_args->sse[ssecount++].i32 = *(UINT32 *) a;
+           memcpy (&reg_args->sse[ssecount++].i32, a, sizeof(UINT32));
            break;
          default:
            abort();
          }
          }
      }
      }
+   reg_args->rax = ssecount;
  
    ffi_call_unix64 (stack, cif->bytes + sizeof (struct register_args),
-            cif->flags, rvalue, fn, ssecount);
+            flags, rvalue, fn);
  }
  
+ #ifndef __ILP32__
+ extern void
+ ffi_call_efi64(ffi_cif *cif, void (*fn)(void), void *rvalue, void **avalue);
+ #endif
  
- extern void ffi_closure_unix64(void);
+ void
+ ffi_call (ffi_cif *cif, void (*fn)(void), void *rvalue, void **avalue)
+ {
+ #ifndef __ILP32__
+   if (cif->abi == FFI_EFI64 || cif->abi == FFI_GNUW64)
+     {
+       ffi_call_efi64(cif, fn, rvalue, avalue);
+       return;
+     }
+ #endif
+   ffi_call_int (cif, fn, rvalue, avalue, NULL);
+ }
+ 
+ #ifndef __ILP32__
+ extern void
+ ffi_call_go_efi64(ffi_cif *cif, void (*fn)(void), void *rvalue,
+           void **avalue, void *closure);
+ #endif
+ 
+ void
+ ffi_call_go (ffi_cif *cif, void (*fn)(void), void *rvalue,
+          void **avalue, void *closure)
+ {
+ #ifndef __ILP32__
+   if (cif->abi == FFI_EFI64 || cif->abi == FFI_GNUW64)
+     {
+       ffi_call_go_efi64(cif, fn, rvalue, avalue, closure);
+       return;
+     }
+ #endif
+   ffi_call_int (cif, fn, rvalue, avalue, closure);
+ }
+ 
+ 
+ extern void ffi_closure_unix64(void) FFI_HIDDEN;
+ extern void ffi_closure_unix64_sse(void) FFI_HIDDEN;
+ 
+ #ifndef __ILP32__
+ extern ffi_status
+ ffi_prep_closure_loc_efi64(ffi_closure* closure,
+                ffi_cif* cif,
+                void (*fun)(ffi_cif*, void*, void**, void*),
+                void *user_data,
+                void *codeloc);
+ #endif
  
  ffi_status
  ffi_prep_closure_loc (ffi_closure* closure,
                ffi_cif* cif,
                void (*fun)(ffi_cif*, void*, void**, void*),
                void *user_data,
                void *codeloc)
  {
-   volatile unsigned short *tramp;
+   static const unsigned char trampoline[16] = {
+     /* leaq  -0x7(%rip),%r10   # 0x0  */
+     0x4c, 0x8d, 0x15, 0xf9, 0xff, 0xff, 0xff,
+     /* jmpq  *0x3(%rip)        # 0x10 */
+     0xff, 0x25, 0x03, 0x00, 0x00, 0x00,
+     /* nopl  (%rax) */
+     0x0f, 0x1f, 0x00
+   };
+   void (*dest)(void);
+   char *tramp = closure->tramp;
  
-   /* Sanity check on the cif ABI.  */
-   {
-     int abi = cif->abi;
-     if (UNLIKELY (! (abi > FFI_FIRST_ABI && abi < FFI_LAST_ABI)))
+ #ifndef __ILP32__
+   if (cif->abi == FFI_EFI64 || cif->abi == FFI_GNUW64)
+     return ffi_prep_closure_loc_efi64(closure, cif, fun, user_data, codeloc);
+ #endif
+   if (cif->abi != FFI_UNIX64)
        return FFI_BAD_ABI;
-   }
- 
-   tramp = (volatile unsigned short *) &closure->tramp[0];
- 
-   tramp[0] = 0xbb49;        /* mov <code>, %r11 */
-   *((unsigned long long * volatile) &tramp[1])
-     = (unsigned long) ffi_closure_unix64;
-   tramp[5] = 0xba49;        /* mov <data>, %r10 */
-   *((unsigned long long * volatile) &tramp[6])
-     = (unsigned long) codeloc;
  
-   /* Set the carry bit iff the function uses any sse registers.
-      This is clc or stc, together with the first byte of the jmp.  */
-   tramp[10] = cif->flags & (1 << 11) ? 0x49f9 : 0x49f8;
+   if (cif->flags & UNIX64_FLAG_XMM_ARGS)
+     dest = ffi_closure_unix64_sse;
+   else
+     dest = ffi_closure_unix64;
  
-   tramp[11] = 0xe3ff;           /* jmp *%r11    */
+   memcpy (tramp, trampoline, sizeof(trampoline));
+   *(UINT64 *)(tramp + 16) = (uintptr_t)dest;
  
    closure->cif = cif;
    closure->fun = fun;
    closure->user_data = user_data;
  
    return FFI_OK;
  }
  
- int
- ffi_closure_unix64_inner(ffi_closure *closure, void *rvalue,
-              struct register_args *reg_args, char *argp)
+ int FFI_HIDDEN
+ ffi_closure_unix64_inner(ffi_cif *cif,
+              void (*fun)(ffi_cif*, void*, void**, void*),
+              void *user_data,
+              void *rvalue,
+              struct register_args *reg_args,
+              char *argp)
  {
-   ffi_cif *cif;
    void **avalue;
    ffi_type **arg_types;
    long i, avn;
    int gprcount, ssecount, ngpr, nsse;
-   int ret;
+   int flags;
  
-   cif = closure->cif;
-   avalue = alloca(cif->nargs * sizeof(void *));
+   avn = cif->nargs;
+   flags = cif->flags;
+   avalue = alloca(avn * sizeof(void *));
    gprcount = ssecount = 0;
  
-   ret = cif->rtype->type;
-   if (ret != FFI_TYPE_VOID)
-     {
-       enum x86_64_reg_class classes[MAX_CLASSES];
-       size_t n = examine_argument (cif->rtype, classes, 1, &ngpr, &nsse);
-       if (n == 0)
+   if (flags & UNIX64_FLAG_RET_IN_MEM)
      {
-       /* The return value goes in memory.  Arrange for the closure
-          return value to go directly back to the original caller.  */
-       rvalue = (void *) (unsigned long) reg_args->gpr[gprcount++];
-       /* We don't have to do anything in asm for the return.  */
-       ret = FFI_TYPE_VOID;
-     }
-       else if (ret == FFI_TYPE_STRUCT && n == 2)
-     {
-       /* Mark which register the second word of the structure goes in.  */
-       _Bool sse0 = SSE_CLASS_P (classes[0]);
-       _Bool sse1 = SSE_CLASS_P (classes[1]);
-       if (!sse0 && sse1)
-         ret |= 1 << 8;
-       else if (sse0 && !sse1)
-         ret |= 1 << 9;
-     }
+       /* On return, %rax will contain the address that was passed
+      by the caller in %rdi.  */
+       void *r = (void *)(uintptr_t)reg_args->gpr[gprcount++];
+       *(void **)rvalue = r;
+       rvalue = r;
+       flags = (sizeof(void *) == 4 ? UNIX64_RET_UINT32 : UNIX64_RET_INT64);
      }
  
-   avn = cif->nargs;
    arg_types = cif->arg_types;
- 
    for (i = 0; i < avn; ++i)
      {
        enum x86_64_reg_class classes[MAX_CLASSES];
        size_t n;
  

@@ -625,11 +806,11 @@
        /* Stack arguments are *always* at least 8 byte aligned.  */
        if (align < 8)
          align = 8;
  
        /* Pass this argument in memory.  */
-       argp = (void *) ALIGN (argp, align);
+       argp = (void *) FFI_ALIGN (argp, align);
        avalue[i] = argp;
        argp += arg_types[i]->size;
      }
        /* If the argument is in a single register, or two consecutive
       integer registers, then we can use that address directly.  */

@@ -651,11 +832,11 @@
      }
        /* Otherwise, allocate space to make them consecutive.  */
        else
      {
        char *a = alloca (16);
-       int j;
+       unsigned int j;
  
        avalue[i] = a;
        for (j = 0; j < n; j++, a += 8)
          {
            if (SSE_CLASS_P (classes[j]))

@@ -665,12 +846,41 @@
          }
      }
      }
  
    /* Invoke the closure.  */
-   closure->fun (cif, rvalue, avalue, closure->user_data);
+   fun (cif, rvalue, avalue, user_data);
  
    /* Tell assembly how to perform return type promotions.  */
-   return ret;
+   return flags;
+ }
+ 
+ extern void ffi_go_closure_unix64(void) FFI_HIDDEN;
+ extern void ffi_go_closure_unix64_sse(void) FFI_HIDDEN;
+ 
+ #ifndef __ILP32__
+ extern ffi_status
+ ffi_prep_go_closure_efi64(ffi_go_closure* closure, ffi_cif* cif,
+               void (*fun)(ffi_cif*, void*, void**, void*));
+ #endif
+ 
+ ffi_status
+ ffi_prep_go_closure (ffi_go_closure* closure, ffi_cif* cif,
+              void (*fun)(ffi_cif*, void*, void**, void*))
+ {
+ #ifndef __ILP32__
+   if (cif->abi == FFI_EFI64 || cif->abi == FFI_GNUW64)
+     return ffi_prep_go_closure_efi64(closure, cif, fun);
+ #endif
+   if (cif->abi != FFI_UNIX64)
+     return FFI_BAD_ABI;
+ 
+   closure->tramp = (cif->flags & UNIX64_FLAG_XMM_ARGS
+             ? ffi_go_closure_unix64_sse
+             : ffi_go_closure_unix64);
+   closure->cif = cif;
+   closure->fun = fun;
+ 
+   return FFI_OK;
  }
  
  #endif /* __x86_64__ */
< prev index next >