Commit 92022496ef7a9439f48a2ef11e460c300ac863d7

Richard Henderson 2014-10-26T14:48:28

sparc: Add support for Go closures

diff --git a/src/sparc/ffi.c b/src/sparc/ffi.c
index d319c03..19c3586 100644
--- a/src/sparc/ffi.c
+++ b/src/sparc/ffi.c
@@ -176,7 +176,7 @@ ffi_prep_cif_machdep(ffi_cif *cif)
 }
 
 extern void ffi_call_v8(ffi_cif *cif, void (*fn)(void), void *rvalue,
-			void **avalue, size_t bytes) FFI_HIDDEN;
+			void **avalue, size_t bytes, void *closure) FFI_HIDDEN;
 
 int FFI_HIDDEN
 ffi_prep_args_v8(ffi_cif *cif, unsigned long *argp, void *rvalue, void **avalue)
@@ -280,8 +280,9 @@ ffi_prep_args_v8(ffi_cif *cif, unsigned long *argp, void *rvalue, void **avalue)
   return flags;
 }
 
-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 bytes = cif->bytes;
 
@@ -292,7 +293,20 @@ ffi_call (ffi_cif *cif, void (*fn)(void), void *rvalue, void **avalue)
   if (rvalue == NULL && cif->flags == SPARC_RET_STRUCT)
     bytes += ALIGN (cif->rtype->size, 8);
 
-  ffi_call_v8(cif, fn, rvalue, avalue, -bytes);
+  ffi_call_v8(cif, fn, rvalue, avalue, -bytes, closure);
+}
+
+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);
 }
 
 #ifdef __GNUC__
@@ -308,6 +322,7 @@ extern void ffi_flush_icache (void *) FFI_HIDDEN;
 #endif
 
 extern void ffi_closure_v8(void) FFI_HIDDEN;
+extern void ffi_go_closure_v8(void) FFI_HIDDEN;
 
 ffi_status
 ffi_prep_closure_loc (ffi_closure *closure,
@@ -337,16 +352,30 @@ ffi_prep_closure_loc (ffi_closure *closure,
   return FFI_OK;
 }
 
+ffi_status
+ffi_prep_go_closure (ffi_go_closure *closure, ffi_cif *cif,
+		     void (*fun)(ffi_cif*, void*, void**, void*))
+{
+  if (cif->abi != FFI_V8)
+    return FFI_BAD_ABI;
+
+  closure->tramp = ffi_go_closure_v8;
+  closure->cif = cif;
+  closure->fun = fun;
+
+  return FFI_OK;
+}
+
 int FFI_HIDDEN
-ffi_closure_sparc_inner_v8(ffi_closure *closure, void *rvalue,
+ffi_closure_sparc_inner_v8(ffi_cif *cif, 
+			   void (*fun)(ffi_cif*, void*, void**, void*),
+			   void *user_data, void *rvalue,
 			   unsigned long *argp)
 {
-  ffi_cif *cif;
   ffi_type **arg_types;
   void **avalue;
   int i, nargs, flags;
 
-  cif = closure->cif;
   arg_types = cif->arg_types;
   nargs = cif->nargs;
   flags = cif->flags;
@@ -424,7 +453,7 @@ ffi_closure_sparc_inner_v8(ffi_closure *closure, void *rvalue,
     }
 
   /* Invoke the closure.  */
-  (closure->fun) (cif, rvalue, avalue, closure->user_data);
+  fun (cif, rvalue, avalue, user_data);
 
   /* Tell ffi_closure_sparc how to perform return type promotions.  */
   return flags;
diff --git a/src/sparc/ffi64.c b/src/sparc/ffi64.c
index 1e2d3f4..02f3d75 100644
--- a/src/sparc/ffi64.c
+++ b/src/sparc/ffi64.c
@@ -305,7 +305,7 @@ ffi_prep_cif_machdep(ffi_cif *cif)
 }
 
 extern void ffi_call_v9(ffi_cif *cif, void (*fn)(void), void *rvalue,
-			void **avalue, size_t bytes) FFI_HIDDEN;
+			void **avalue, size_t bytes, void *closure) FFI_HIDDEN;
 
 /* ffi_prep_args is called by the assembly routine once stack space
    has been allocated for the function's arguments */
@@ -402,8 +402,9 @@ ffi_prep_args_v9(ffi_cif *cif, unsigned long *argp, void *rvalue, void **avalue)
   return flags;
 }
 
-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 bytes = cif->bytes;
 
@@ -412,7 +413,20 @@ ffi_call(ffi_cif *cif, void (*fn)(void), void *rvalue, void **avalue)
   if (rvalue == NULL && (cif->flags & SPARC_FLAG_RET_IN_MEM))
     bytes += ALIGN (cif->rtype->size, 16);
 
-  ffi_call_v9(cif, fn, rvalue, avalue, -bytes);
+  ffi_call_v9(cif, fn, rvalue, avalue, -bytes, closure);
+}
+
+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);
 }
 
 #ifdef __GNUC__
@@ -426,6 +440,7 @@ extern void ffi_flush_icache (void *) FFI_HIDDEN;
 #endif
 
 extern void ffi_closure_v9(void) FFI_HIDDEN;
+extern void ffi_go_closure_v9(void) FFI_HIDDEN;
 
 ffi_status
 ffi_prep_closure_loc (ffi_closure* closure,
@@ -458,16 +473,30 @@ ffi_prep_closure_loc (ffi_closure* closure,
   return FFI_OK;
 }
 
+ffi_status
+ffi_prep_go_closure (ffi_go_closure* closure, ffi_cif* cif,
+		     void (*fun)(ffi_cif*, void*, void**, void*))
+{
+  if (cif->abi != FFI_V9)
+    return FFI_BAD_ABI;
+
+  closure->tramp = ffi_go_closure_v9;
+  closure->cif = cif;
+  closure->fun = fun;
+
+  return FFI_OK;
+}
+
 int FFI_HIDDEN
-ffi_closure_sparc_inner_v9(ffi_closure *closure, void *rvalue,
+ffi_closure_sparc_inner_v9(ffi_cif *cif,
+			   void (*fun)(ffi_cif*, void*, void**, void*),
+			   void *user_data, void *rvalue,
 			   unsigned long *gpr, unsigned long *fpr)
 {
-  ffi_cif *cif;
   ffi_type **arg_types;
   void **avalue;
   int i, argn, argx, nargs, flags;
 
-  cif = closure->cif;
   arg_types = cif->arg_types;
   nargs = cif->nargs;
   flags = cif->flags;
@@ -555,7 +584,7 @@ ffi_closure_sparc_inner_v9(ffi_closure *closure, void *rvalue,
     }
 
   /* Invoke the closure.  */
-  (closure->fun) (cif, rvalue, avalue, closure->user_data);
+  fun (cif, rvalue, avalue, user_data);
 
   /* Tell ffi_closure_sparc how to perform return type promotions.  */
   return flags;
diff --git a/src/sparc/ffitarget.h b/src/sparc/ffitarget.h
index f70c937..6982903 100644
--- a/src/sparc/ffitarget.h
+++ b/src/sparc/ffitarget.h
@@ -63,6 +63,7 @@ typedef enum ffi_abi {
 /* ---- Definitions for closures ----------------------------------------- */
 
 #define FFI_CLOSURES 1
+#define FFI_GO_CLOSURES 1
 #define FFI_NATIVE_RAW_API 0
 
 #ifdef SPARC64
diff --git a/src/sparc/v8.S b/src/sparc/v8.S
index e76d813..66cf76f 100644
--- a/src/sparc/v8.S
+++ b/src/sparc/v8.S
@@ -102,7 +102,7 @@ C(ffi_call_v8):
 
 	! Call foreign function
 	call	%i1
-	 nop
+	 mov	%i5, %g2		! load static chain
 
 0:	call	1f		! load pc in %o7
 	 sll	%l0, 4, %l0
@@ -185,7 +185,7 @@ E SPARC_RET_F_1
 	! Struct returning functions expect and skip the unimp here.
 	.align	8
 8:	call	%i1
-	 nop
+	 mov	%i5, %g2		! load static chain
 	unimp	4
 	ret
 	 restore
@@ -211,20 +211,43 @@ E SPARC_RET_F_1
 
    Receives the closure argument in %g2.   */
 
+#ifdef HAVE_AS_REGISTER_PSEUDO_OP
+	.register	%g2, #scratch
+#endif
+
+	.align 8
+	.globl	C(ffi_go_closure_v8)
+	.type	C(ffi_go_closure_v8),@function
+	FFI_HIDDEN(C(ffi_go_closure_v8))
+
+C(ffi_go_closure_v8):
+	cfi_startproc
+	save	%sp, -STACKFRAME, %sp
+	cfi_def_cfa_register(%fp)
+	cfi_window_save
+
+	ld	[%g2+4], %o0			! load cif
+	ld	[%g2+8], %o1			! load fun
+	b	0f
+	 mov	%g2, %o2			! load user_data
+	cfi_endproc
+	.size	C(ffi_go_closure_v8), . - C(ffi_go_closure_v8)
+
 	.align 8
 	.globl	C(ffi_closure_v8)
 	.type	C(ffi_closure_v8),@function
 	FFI_HIDDEN(C(ffi_closure_v8))
 
 C(ffi_closure_v8):
-#ifdef HAVE_AS_REGISTER_PSEUDO_OP
-		.register	%g2, #scratch
-#endif
 	cfi_startproc
 	save	%sp, -STACKFRAME, %sp
 	cfi_def_cfa_register(%fp)
 	cfi_window_save
 
+	ld	[%g2+FFI_TRAMPOLINE_SIZE], %o0		! load cif
+	ld	[%g2+FFI_TRAMPOLINE_SIZE+4], %o1	! load fun
+	ld	[%g2+FFI_TRAMPOLINE_SIZE+8], %o2	! load user_data
+0:
 	! Store all of the potential argument registers in va_list format.
 	st	%i0, [%fp+68+0]
 	st	%i1, [%fp+68+4]
@@ -234,10 +257,9 @@ C(ffi_closure_v8):
 	st	%i5, [%fp+68+20]
 
 	! Call ffi_closure_sparc_inner to do the bulk of the work.
-	mov	%g2, %o0
-	add	%fp, -8*4, %o1
+	add	%fp, -8*4, %o3
 	call	ffi_closure_sparc_inner_v8
-	 add	%fp,  64, %o2
+	 add	%fp,  64, %o4
 
 0:	call	1f
 	 and	%o0, SPARC_FLAG_RET_MASK, %o0
diff --git a/src/sparc/v9.S b/src/sparc/v9.S
index 5c3f27b..d848f9a 100644
--- a/src/sparc/v9.S
+++ b/src/sparc/v9.S
@@ -94,8 +94,9 @@ C(ffi_call_v9):
 	ldx	[%sp+STACK_BIAS+128+16], %o2
 	ldx	[%sp+STACK_BIAS+128+24], %o3
 	ldx	[%sp+STACK_BIAS+128+32], %o4
+	ldx	[%sp+STACK_BIAS+128+40], %o5
 	call	%i1
-	 ldx	[%sp+STACK_BIAS+128+40], %o5
+	 mov	%i5, %g5			! load static chain
 
 0:	call	1f		! load pc in %o7
 	 and	%l0, SPARC_FLAG_RET_MASK, %l1
@@ -211,6 +212,25 @@ E SPARC_RET_F_1
    Receives the closure argument in %g1.   */
 
 	.align 8
+	.globl	C(ffi_go_closure_v9)
+	.type	C(ffi_go_closure_v9),@function
+	FFI_HIDDEN(C(ffi_go_closure_v9))
+
+C(ffi_go_closure_v9):
+	cfi_startproc
+	save	%sp, -STACKFRAME, %sp
+	cfi_def_cfa_register(%fp)
+	cfi_window_save
+
+	ldx	[%g5+8], %o0
+	ldx	[%g5+16], %o1
+	b	0f
+	 mov	%g5, %o2
+
+	cfi_endproc
+	.size	C(ffi_go_closure_v9), . - C(ffi_go_closure_v9)
+
+	.align 8
 	.globl	C(ffi_closure_v9)
 	.type	C(ffi_closure_v9),@function
 	FFI_HIDDEN(C(ffi_closure_v9))
@@ -221,6 +241,10 @@ C(ffi_closure_v9):
 	cfi_def_cfa_register(%fp)
 	cfi_window_save
 
+	ldx	[%g1+FFI_TRAMPOLINE_SIZE], %o0
+	ldx	[%g1+FFI_TRAMPOLINE_SIZE+8], %o1
+	ldx	[%g1+FFI_TRAMPOLINE_SIZE+16], %o2
+0:
 	! Store all of the potential argument registers in va_list format.
 	stx	%i0, [FP+128+0]
 	stx	%i1, [FP+128+8]
@@ -248,11 +272,10 @@ C(ffi_closure_v9):
 	std     %f30, [FP-8]
 
 	! Call ffi_closure_sparc_inner to do the bulk of the work.
-	mov	%g1, %o0
-	add	%fp, STACK_BIAS-160, %o1
-	add	%fp, STACK_BIAS+128, %o2
+	add	%fp, STACK_BIAS-160, %o3
+	add	%fp, STACK_BIAS+128, %o4
 	call	C(ffi_closure_sparc_inner_v9)
-	 add	%fp, STACK_BIAS-128, %o3
+	 add	%fp, STACK_BIAS-128, %o5
 
 0:	call	1f		! load pc in %o7
 	 and	%o0, SPARC_FLAG_RET_MASK, %o0