diff a/modules/javafx.media/src/main/native/gstreamer/3rd_party/libffi/src/x86/ffi64.c b/modules/javafx.media/src/main/native/gstreamer/3rd_party/libffi/src/x86/ffi64.c
--- a/modules/javafx.media/src/main/native/gstreamer/3rd_party/libffi/src/x86/ffi64.c
+++ b/modules/javafx.media/src/main/native/gstreamer/3rd_party/libffi/src/x86/ffi64.c
@@ -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__ */
