public inbox for libffi-discuss@sourceware.org
 help / color / mirror / Atom feed
From: Richard Henderson <rth@redhat.com>
To: gcc-patches@gcc.gnu.org
Cc: libffi-discuss@sourceware.org,	gofrontend-dev@googlegroups.com
Subject: [PATCH 13/13] libffi: Support go closures on i386
Date: Fri, 10 Oct 2014 20:43:00 -0000	[thread overview]
Message-ID: <1412973773-3942-14-git-send-email-rth@redhat.com> (raw)
In-Reply-To: <1412973773-3942-1-git-send-email-rth@redhat.com>

---
 libffi/src/x86/ffi.c  |  88 ++++++++++++++++++++++++++++++++++++-----
 libffi/src/x86/sysv.S | 107 +++++++++++++++++++++++++++++++++++++++++---------
 2 files changed, 166 insertions(+), 29 deletions(-)

diff --git a/libffi/src/x86/ffi.c b/libffi/src/x86/ffi.c
index e3f82ef..77abbe3 100644
--- a/libffi/src/x86/ffi.c
+++ b/libffi/src/x86/ffi.c
@@ -162,8 +162,9 @@ struct ffi_call_frame
 extern void ffi_call_i386(struct ffi_call_frame *, char *)
 	FFI_HIDDEN __attribute__((fastcall));
 
-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)
 {
   size_t rsize;
   struct ffi_call_frame *frame;
@@ -206,6 +207,21 @@ ffi_call(ffi_cif *cif, void (*fn)(void), void *rvalue, void **avalue)
   frame->flags = flags;
   frame->rvalue = rvalue;
 
+  /* Install the closure as the static chain value.  Note that the
+     static chain isn't part of an official ABI, it's what gcc itself
+     allocates for a given ABI.  Generally, this is a register that's
+     predictably unused on entry.  */
+  switch (cabi)
+    {
+    case FFI_THISCALL:
+    case FFI_FASTCALL:
+      frame->eax = (unsigned)closure;
+      break;
+    default:
+      frame->ecx = (unsigned)closure;
+      break;
+    }
+
   narg_reg = 0;
   switch (flags)
     {
@@ -265,6 +281,20 @@ ffi_call(ffi_cif *cif, void (*fn)(void), void *rvalue, void **avalue)
   ffi_call_i386(frame, stack);
 }
 
+void
+ffi_call (ffi_cif *cif, void (*fn)(void), void *rvalue, void **avalue)
+{
+  ffi_call_int (cif, fn, rvalue, avalue, NULL);
+}
+
+void
+ffi_call_go (ffi_cif *cif, void (*fn)(void), void *rvalue,
+	     void **avalue, void *closure)
+{
+  ffi_call_int (cif, fn, rvalue, avalue, closure);
+}
+
+
 /* ------- Closure API support ----------------------------------- */
 
 /* How to make a trampoline.  Derived from gcc/config/i386/i386.c. */
@@ -321,18 +351,19 @@ ffi_prep_closure_loc (ffi_closure* closure,
 
 struct ffi_closure_frame
 {
-  unsigned rettemp[4];	/* 0 */
-  unsigned eax;		/* 16 */
-  unsigned edx;		/* 20 */
-  unsigned ecx;		/* 24 */
-  ffi_closure *closure;	/* 28 */
+  unsigned rettemp[4];				/* 0 */
+  unsigned eax;					/* 16 */
+  unsigned edx;					/* 20 */
+  unsigned ecx;					/* 24 */
+  ffi_cif *cif;					/* 28 */
+  void (*fun)(ffi_cif*,void*,void**,void*);	/* 32 */
+  void *user_data;				/* 36 */
 };
 
 unsigned int FFI_HIDDEN __attribute__ ((fastcall))
 ffi_closure_inner (struct ffi_closure_frame *frame, char *argp)
 {
-  ffi_closure *closure = frame->closure;
-  ffi_cif *cif = closure->cif;
+  ffi_cif *cif = frame->cif;
   int cabi, i, n, flags, narg_reg;
   ffi_type **arg_types;
   void *rvalue;
@@ -389,7 +420,7 @@ ffi_closure_inner (struct ffi_closure_frame *frame, char *argp)
       avalue[i] = valp;
     }
 
-  closure->fun (cif, rvalue, avalue, closure->user_data);
+  frame->fun (cif, rvalue, avalue, frame->user_data);
 
   if (cabi == FFI_STDCALL)
     return flags + (cif->bytes << X86_RET_POP_SHIFT);
@@ -559,4 +590,41 @@ ffi_raw_call(ffi_cif *cif, void (*fn)(void), void *rvalue, ffi_raw *avalue)
   ffi_call_i386(frame, stack);
 }
 
+/* ------- Go API support ---------------------------------------- */
+
+extern void ffi_go_closure_eax (void) FFI_HIDDEN;
+extern void ffi_go_closure_ecx (void) FFI_HIDDEN;
+extern void ffi_go_closure_stdcall (void) FFI_HIDDEN;
+
+ffi_status
+ffi_prep_go_closure (ffi_go_closure* closure, ffi_cif* cif,
+		     void (*fun)(ffi_cif*, void*, void**, void*))
+{
+  void (*dest)(void);
+
+  /* See the comment in ffi_call_int about the static chain.  */
+  switch (cif->abi)
+    {
+    case FFI_SYSV:
+    case FFI_MS_CDECL:
+      dest = ffi_go_closure_ecx;
+      break;
+    case FFI_THISCALL:
+    case FFI_FASTCALL:
+      dest = ffi_go_closure_eax;
+      break;
+    case FFI_STDCALL:
+      dest = ffi_go_closure_stdcall;
+      break;
+    default:
+      return FFI_BAD_ABI;
+    }
+
+  closure->tramp = dest;
+  closure->cif = cif;
+  closure->fun = fun;
+
+  return FFI_OK;
+}
+
 #endif /* !__x86_64__ */
diff --git a/libffi/src/x86/sysv.S b/libffi/src/x86/sysv.S
index d8256d0..2709b11 100644
--- a/libffi/src/x86/sysv.S
+++ b/libffi/src/x86/sysv.S
@@ -165,26 +165,37 @@ E X86_RET_UNUSED15
 	.cfi_endproc
 	.size	ffi_call_i386, . - ffi_call_i386
 
-/* The closure entry points are reached from the ffi_closure trampoline.
-   On entry, %eax contains the address of the ffi_closure.  */
-
-#define	ffi_closure_FS	(12 + 4*4 + 16)
+#define	ffi_closure_FS	(4 + 3*4 + 3*4 + 16)
 
-.macro FFI_CLOSURE_FIRST
-	subl	$ffi_closure_FS, %esp
-	.cfi_adjust_cfa_offset ffi_closure_FS
+/* Macros to help setting up the ffi_closure_data structure.  */
 
-	movl	%edx, 20(%esp)		/* save incoming register args */
+.macro FFI_CLOSURE_SAVE_REGS
+	movl	%eax, 16(%esp)		/* save incoming register args */
+	movl	%edx, 20(%esp)
 	movl	%ecx, 24(%esp)
-	movl	%eax, 28(%esp)		/* trampoline loaded closure */
+.endm
+
+.macro FFI_CLOSURE_COPY_TRAMP_DATA
+	movl	12(%eax), %edx		/* copy cif */
+	movl	16(%eax), %ecx		/* copy fun */
+	movl	20(%eax), %eax		/* copy user_data */
+	movl	%edx, 28(%esp)
+	movl	%ecx, 32(%esp)
+	movl	%eax, 36(%esp)
+.endm
 
-	movl	%esp, %ecx		/* pass save area to C */
-	leal	ffi_closure_FS+4(%esp), %edx
+.macro FFI_CLOSURE_COPY_USER_DATA base, ofs, t1
+	movl	\ofs(\base), \t1
+	movl	\t1, 36(%esp)
+.endm
 
+.macro FFI_CLOSURE_CALL_INNER
+	movl	%esp, %ecx			/* load ffi_closure_data */
+	leal	ffi_closure_FS+4(%esp), %edx	/* load incoming stack */
 #ifdef __PIC__
-	movl	%ebx, 32(%esp)		/* save ebx */
+	movl	%ebx, 40(%esp)			/* save ebx */
 	.cfi_rel_offset %esp, 32
-	call	__x86.get_pc_thunk.bx
+	call	__x86.get_pc_thunk.bx		/* load got register */
 	addl	$_GLOBAL_OFFSET_TABLE_, %ebx
 #endif
 #if defined HAVE_HIDDEN_VISIBILITY_ATTRIBUTE || !defined __PIC__
@@ -194,11 +205,11 @@ E X86_RET_UNUSED15
 #endif
 .endm
 
-.macro FFI_CLOSURE_SECOND
+.macro FFI_CLOSURE_MASK_AND_JUMP
 	andl	$X86_RET_TYPE_MASK, %eax
 #ifdef __PIC__
 	leal	0f@GOTOFF(%ebx, %eax, 8), %eax
-	movl	32(%esp), %ebx		/* restore ebx */
+	movl	40(%esp), %ebx		/* restore ebx */
 	.cfi_restore %ebx
 #else
 	leal	0f(, %eax, 8), %eax
@@ -206,6 +217,36 @@ E X86_RET_UNUSED15
 	jmp	*%eax
 .endm
 
+/* The go closure entry points are called directly from Go code.
+   The suffix is the register in which the static chain is located.  */
+
+
+.macro FFI_GO_CLOSURE	suffix, chain, t1, t2
+	.align	16
+	.globl	ffi_go_closure_\suffix
+	.type	ffi_go_closure_\suffix, @function
+	FFI_HIDDEN (ffi_go_closure_\suffix)
+ffi_go_closure_\suffix:
+	.cfi_startproc
+	subl	$ffi_closure_FS, %esp
+	.cfi_adjust_cfa_offset ffi_closure_FS
+	FFI_CLOSURE_SAVE_REGS
+	movl	4(\chain), \t1		/* copy cif */
+	movl	8(\chain), \t2		/* copy fun */
+	movl	\t1, 28(%esp)
+	movl	\t2, 32(%esp)
+	movl	\chain, 36(%esp)	/* closure is user_data  */
+	jmp	88f
+	.cfi_endproc
+	.size	ffi_go_closure_\suffix, . - ffi_go_closure_\suffix
+.endm
+
+FFI_GO_CLOSURE	eax, %eax, %edx, %ecx
+FFI_GO_CLOSURE	ecx, %ecx, %edx, %eax
+
+/* The closure entry points are reached from the ffi_closure trampoline.
+   On entry, %eax contains the address of the ffi_closure.  */
+
 	.align	16
 	.globl	ffi_closure_i386
 	.type	ffi_closure_i386, @function
@@ -213,8 +254,16 @@ E X86_RET_UNUSED15
 
 ffi_closure_i386:
 	.cfi_startproc
-	FFI_CLOSURE_FIRST
-	FFI_CLOSURE_SECOND
+	subl	$ffi_closure_FS, %esp
+	.cfi_adjust_cfa_offset ffi_closure_FS
+
+	FFI_CLOSURE_SAVE_REGS
+	FFI_CLOSURE_COPY_TRAMP_DATA
+
+88:	/* Entry point from preceeding Go closures.  */
+
+	FFI_CLOSURE_CALL_INNER
+	FFI_CLOSURE_MASK_AND_JUMP
 
 	.align	8
 0:
@@ -284,6 +333,8 @@ E X86_RET_UNUSED15
 	.cfi_endproc
 	.size	ffi_closure_i386, . - ffi_closure_i386
 
+FFI_GO_CLOSURE	stdcall, %ecx, %edx, %eax
+
 	.align	16
 	.globl	ffi_closure_i386_stdcall
 	.type	ffi_closure_i386_stdcall, @function
@@ -291,16 +342,34 @@ E X86_RET_UNUSED15
 
 ffi_closure_i386_stdcall:
 	.cfi_startproc
-	FFI_CLOSURE_FIRST
+	subl	$ffi_closure_FS, %esp
+	.cfi_adjust_cfa_offset ffi_closure_FS
+
+	FFI_CLOSURE_SAVE_REGS
+	FFI_CLOSURE_COPY_TRAMP_DATA
+
+88:	/* Entry point from preceeding Go closure.  */
+
+	FFI_CLOSURE_CALL_INNER
 
 	movl	%eax, %ecx
 	shrl	$4, %ecx			    /* isolate pop count */
 	leal	ffi_closure_FS(%esp, %ecx), %ecx    /* compute popped esp */
 	movl	ffi_closure_FS(%esp), %edx	    /* move return address */
 	movl	%edx, (%ecx)
+
+	/* New pseudo-stack frame based off ecx.  This is unwind trickery
+	   in that the CFA *has* changed, to the proper popped stack address.
+	   Note that the location to which we moved the return address
+	   is (the new) CFA-4, so that's unchanged.  */
 	.cfi_def_cfa %ecx, 4
+	/* Normally esp is unwound to CFA + the caller's ARGS_SIZE.
+	   We've just set the CFA to that final value.  Tell the unwinder
+	   to restore esp from CFA without the ARGS_SIZE:
+	   DW_CFA_val_expression %esp, DW_OP_call_frame_cfa.  */
+	.cfi_escape 0x16, 4, 1, 0x9c
 
-	FFI_CLOSURE_SECOND
+	FFI_CLOSURE_MASK_AND_JUMP
 
 	.align	8
 0:
-- 
1.9.3

  parent reply	other threads:[~2014-10-10 20:43 UTC|newest]

Thread overview: 43+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2014-10-10 20:43 [PATCH 00/13] Go closures, libffi, and the static chain Richard Henderson
2014-10-10 20:43 ` [PATCH 02/13] Allow the front-end to create calls with a " Richard Henderson
2014-10-10 20:43 ` [PATCH 08/13] libgo: Use the new libffi interfaces for Go Richard Henderson
2014-10-10 20:43 ` [PATCH 07/13] libffi: Support go closures on x86_64 Richard Henderson
2014-10-10 20:43 ` [PATCH 09/13] libgo: Remove __go_get/set_closure Richard Henderson
2014-10-10 20:43 ` [PATCH 01/13] Make TARGET_STATIC_CHAIN allow a function type Richard Henderson
2014-10-10 20:43 ` [PATCH 03/13] HACK! Allow the static chain to be set from C Richard Henderson
2014-10-11  0:33   ` Ian Lance Taylor
     [not found]     ` <CAMn1gO7vJOcNi218p9m32de_rrnKBrUcGF-EKP3dJwaL+8BtUw@mail.gmail.com>
2014-10-11  1:42       ` [gofrontend-dev] " Peter Collingbourne
2014-10-11  4:24         ` Richard Henderson
2014-10-13  8:10           ` Richard Biener
2014-10-13 18:46             ` Peter Collingbourne
2014-10-14 18:44   ` [PATCH v2 03/13] " Richard Henderson
2014-10-10 20:43 ` Richard Henderson [this message]
2014-10-10 20:43 ` [PATCH 06/13] libffi: Add entry points for interacting with Go Richard Henderson
2014-10-10 20:43 ` [PATCH 11/13] libffi: Support go closures on aarch64 Richard Henderson
2014-10-10 20:43 ` [PATCH 04/13] Use the static chain as the closure parameter from Go Richard Henderson
2014-10-10 20:43 ` [PATCH 12/13] libffi: Rewrite i386 sysv Richard Henderson
2014-10-10 20:43 ` [PATCH 10/13] libffi: Rewrite aarch64 Richard Henderson
2014-10-10 20:43 ` [PATCH 05/13] libgo: Use the static chain for the closure Richard Henderson
2014-10-11  0:23 ` [PATCH 00/13] Go closures, libffi, and the static chain Ian Lance Taylor
2014-11-05 21:34 ` Lynn A. Boger
2014-11-06  6:59   ` Richard Henderson
2014-11-06 12:48     ` Alan Modra
2014-11-06 13:04       ` Richard Henderson
2014-11-06 17:45         ` [gofrontend-dev] " Ian Taylor
2014-11-07  7:39           ` Richard Henderson
2014-11-07  8:50             ` Jay
2014-11-07 16:06             ` Ian Taylor
2014-11-07 23:55               ` Alan Modra
2014-11-06 13:10       ` Lynn A. Boger
2014-11-06 13:17         ` Richard Henderson
2014-12-11  9:06 ` Dominik Vogt
2014-12-11  9:21   ` Alan Modra
2014-12-11 10:31     ` [gofrontend-dev] " Dominik Vogt
2014-12-11 12:25       ` Dominik Vogt
2014-12-11 19:56         ` Richard Henderson
2014-12-12 12:06           ` Dominik Vogt
2014-12-12 18:14             ` Richard Henderson
2014-12-15  9:42               ` Dominik Vogt
2014-12-15 20:11                 ` Richard Henderson
2014-12-12 13:57     ` Dominik Vogt
2014-12-11 19:38   ` Richard Henderson

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1412973773-3942-14-git-send-email-rth@redhat.com \
    --to=rth@redhat.com \
    --cc=gcc-patches@gcc.gnu.org \
    --cc=gofrontend-dev@googlegroups.com \
    --cc=libffi-discuss@sourceware.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).