libffi: closures for sparc

Jeff Sturm jsturm@one-point.com
Wed Jul 17 07:55:00 GMT 2002


I've finished enough of the closure API for sparc to enable the libgcj
bytecode interpreter for sparc and sparc64.  Notes on the implementation:

a) Stack-allocated trampolines Just Don't Work on Solaris unless you
arrange for the stack to be executable, somehow.  Gcc relies on a mprotect
hack to get around this.  I've chosen to eschew this hack in libffi since
libgcj doesn't need it.  The only code I'm aware of that breaks is the
libffi testsuite, so the simplest thing to do is fix the testsuite.

b) The mess in java_raw_api.c is mostly caused by treating the `raw'
argument to ffi_java_raw_call as a pointer to ffi_raw, when it is really a
pointer to _Jv_word.  The two unions are not compatible, or even close.
For instance ffi_raw may not have a 32-bit integer member resembling a
`jint'.

This whole file ought to be looked at more closely, since it seems to be
using ffi_raw as something it isn't.  I'd expect ppc64 to have the same
problems as sparc64.

c) I didn't do any testing on FFI_TYPE_STRUCT arguments to closures.
There are currently no such tests, hence no failures.  I have little
interest in adding test cases since they are irrelevant to gcj.  If
someone else contributes test cases for structs I'll take a look.

d) sparc64 closures will fail in circumstances such as fp args and
variadic functions or functions without prototypes.  I could find
no portable way to accomodate these in libffi at this time.

Tested on sparc-sun-solaris2.8 with GNU binutils and Sun as/ld.  I'm
interested in feedback from sparc-linux and powerpc users.

2002-07-17  Jeff Sturm  <jsturm@one-point.com>

	* include/ffi.h.in: Add closure defines for SPARC, SPARC64.
	* src/ffitest.c (main): Use static storage for closure.
	* src/java_raw_api.c (ffi_java_raw_to_ptrarray,
	ffi_java_ptrarray_to_raw): For WORDS_BIGENDIAN, handle
	raw argument as a _Jv_word.
	* src/sparc/ffi.c (ffi_prep_closure, ffi_closure_sparc_inner): New.
	* src/sparc/v8.S (ffi_closure_v8): New.
	* src/sparc/v9.S (ffi_closure_v9): New.

Index: include/ffi.h.in
===================================================================
RCS file: /cvs/gcc/gcc/libffi/include/ffi.h.in,v
retrieving revision 1.15
diff -u -p -r1.15 ffi.h.in
--- include/ffi.h.in	29 Apr 2002 04:14:44 -0000	1.15
+++ include/ffi.h.in	17 Jul 2002 04:56:46 -0000
@@ -430,6 +430,18 @@ struct ffi_ia64_trampoline_struct {
 #define FFI_TRAMPOLINE_SIZE 24 /* see struct below */
 #define FFI_NATIVE_RAW_API 0

+#elif defined(SPARC64)
+
+#define FFI_CLOSURES 1
+#define FFI_TRAMPOLINE_SIZE 24
+#define FFI_NATIVE_RAW_API 0
+
+#elif defined(SPARC)
+
+#define FFI_CLOSURES 1
+#define FFI_TRAMPOLINE_SIZE 16
+#define FFI_NATIVE_RAW_API 0
+
 #else

 #define FFI_CLOSURES 0
Index: src/ffitest.c
===================================================================
RCS file: /cvs/gcc/gcc/libffi/src/ffitest.c,v
retrieving revision 1.6
diff -u -p -r1.6 ffitest.c
--- src/ffitest.c	24 Feb 2002 17:31:45 -0000	1.6
+++ src/ffitest.c	17 Jul 2002 04:56:46 -0000
@@ -704,7 +704,9 @@ int main(/*@unused@*/ int argc, /*@unuse
 # if FFI_CLOSURES
   /* A simple closure test */
     {
-      ffi_closure cl;
+      /* The closure must not be an automatic variable on
+	 platforms (Solaris) that forbid stack execution by default. */
+      static ffi_closure cl;
       ffi_type * cl_arg_types[3];

       cl_arg_types[0] = &ffi_type_sint;
Index: src/java_raw_api.c
===================================================================
RCS file: /cvs/gcc/gcc/libffi/src/java_raw_api.c,v
retrieving revision 1.2
diff -u -p -r1.2 java_raw_api.c
--- src/java_raw_api.c	8 Apr 2002 23:59:13 -0000	1.2
+++ src/java_raw_api.c	17 Jul 2002 04:56:46 -0000
@@ -81,21 +81,14 @@ ffi_java_raw_to_ptrarray (ffi_cif *cif,
 	{
 	case FFI_TYPE_UINT8:
 	case FFI_TYPE_SINT8:
-	  *args = (void*) ((char*)(raw++) + SIZEOF_ARG - 1);
+	  *args = (void*) ((char*)(raw++) + 3);
 	  break;

 	case FFI_TYPE_UINT16:
 	case FFI_TYPE_SINT16:
-	  *args = (void*) ((char*)(raw++) + SIZEOF_ARG - 2);
+	  *args = (void*) ((char*)(raw++) + 2);
 	  break;

-#if SIZEOF_ARG >= 4
-	case FFI_TYPE_UINT32:
-	case FFI_TYPE_SINT32:
-	  *args = (void*) ((char*)(raw++) + SIZEOF_ARG - 4);
-	  break;
-#endif
-
 #if SIZEOF_ARG == 8
 	case FFI_TYPE_UINT64:
 	case FFI_TYPE_SINT64:
@@ -157,31 +150,54 @@ ffi_java_ptrarray_to_raw (ffi_cif *cif,
       switch ((*tp)->type)
 	{
 	case FFI_TYPE_UINT8:
+#if WORDS_BIGENDIAN
+	  *(UINT32*)(raw++) = *(UINT8*) (*args);
+#else
 	  (raw++)->uint = *(UINT8*) (*args);
+#endif
 	  break;

 	case FFI_TYPE_SINT8:
+#if WORDS_BIGENDIAN
+	  *(SINT32*)(raw++) = *(SINT8*) (*args);
+#else
 	  (raw++)->sint = *(SINT8*) (*args);
+#endif
 	  break;

 	case FFI_TYPE_UINT16:
+#if WORDS_BIGENDIAN
+	  *(UINT32*)(raw++) = *(UINT16*) (*args);
+#else
 	  (raw++)->uint = *(UINT16*) (*args);
+#endif
 	  break;

 	case FFI_TYPE_SINT16:
+#if WORDS_BIGENDIAN
+	  *(SINT32*)(raw++) = *(SINT16*) (*args);
+#else
 	  (raw++)->sint = *(SINT16*) (*args);
+#endif
 	  break;

-#if SIZEOF_ARG >= 4
 	case FFI_TYPE_UINT32:
+#if WORDS_BIGENDIAN
+	  *(UINT32*)(raw++) = *(UINT32*) (*args);
+#else
 	  (raw++)->uint = *(UINT32*) (*args);
+#endif
 	  break;

 	case FFI_TYPE_SINT32:
+#if WORDS_BIGENDIAN
+	  *(SINT32*)(raw++) = *(SINT32*) (*args);
+#else
 	  (raw++)->sint = *(SINT32*) (*args);
-	  break;
 #endif
-        case FFI_TYPE_FLOAT:
+	  break;
+
+	case FFI_TYPE_FLOAT:
 	  (raw++)->flt = *(FLOAT32*) (*args);
 	  break;

Index: src/sparc/ffi.c
===================================================================
RCS file: /cvs/gcc/gcc/libffi/src/sparc/ffi.c,v
retrieving revision 1.3
diff -u -p -r1.3 ffi.c
--- src/sparc/ffi.c	2 Mar 2001 22:21:23 -0000	1.3
+++ src/sparc/ffi.c	17 Jul 2002 04:56:46 -0000
@@ -28,6 +28,12 @@

 #include <stdlib.h>

+#ifdef SPARC64
+extern void ffi_closure_v9(void);
+#else
+extern void ffi_closure_v8(void);
+#endif
+
 /* ffi_prep_args is called by the assembly routine once stack space
    has been allocated for the function's arguments */

@@ -419,4 +425,102 @@ void ffi_call(ffi_cif *cif, void (*fn)()
       break;
     }

+}
+
+ffi_status
+ffi_prep_closure (ffi_closure* closure,
+		  ffi_cif* cif,
+		  void (*fun)(ffi_cif*, void*, void**, void*),
+		  void *user_data)
+{
+  unsigned int *tramp = (unsigned int *) &closure->tramp[0];
+  unsigned long fn;
+  unsigned long ctx = (unsigned long) closure;
+
+#ifdef SPARC64
+  /* Trampoline address is equal to the closure address.  We take advantage
+     of that to reduce the trampoline size by 8 bytes. */
+  FFI_ASSERT (cif->abi == FFI_V9);
+  fn = (unsigned long) ffi_closure_v9;
+  tramp[0] = 0x83414000;	/* rd	%pc, %g1	*/
+  tramp[1] = 0xca586010;	/* ldx	[%g1+16], %g5	*/
+  tramp[2] = 0x81c14000;	/* jmp	%g5		*/
+  tramp[3] = 0x01000000;	/* nop			*/
+  *((unsigned long *) &tramp[4]) = fn;
+#else
+  FFI_ASSERT (cif->abi == FFI_V8);
+  fn = (unsigned long) ffi_closure_v8;
+  tramp[0] = 0x03000000 | fn >> 10;	/* sethi %hi(fn), %g1	*/
+  tramp[1] = 0x05000000 | ctx >> 10;	/* sethi %hi(ctx), %g2	*/
+  tramp[2] = 0x81c06000 | (fn & 0x3ff);	/* jmp   %g1+%lo(fn)	*/
+  tramp[3] = 0x8410a000 | (ctx & 0x3ff);/* or    %g2, %lo(ctx)	*/
+#endif
+
+  closure->cif = cif;
+  closure->fun = fun;
+  closure->user_data = user_data;
+
+  /* Flush the Icache.  FIXME: alignment isn't certain, assume 8 bytes */
+#ifdef SPARC64
+  asm volatile ("flush	%0" : : "r" (closure) : "memory");
+  asm volatile ("flush	%0" : : "r" (((char *) closure) + 8) : "memory");
+#else
+  asm volatile ("iflush	%0" : : "r" (closure) : "memory");
+  asm volatile ("iflush	%0" : : "r" (((char *) closure) + 8) : "memory");
+#endif
+
+  return FFI_OK;
+}
+
+int
+ffi_closure_sparc_inner(ffi_closure *closure,
+  void *rvalue, unsigned long *gpr, double *fpr)
+{
+  ffi_cif *cif;
+  void **avalue;
+  ffi_type **arg_types;
+  int i, avn, argn;
+
+  cif = closure->cif;
+  avalue = alloca(cif->nargs * sizeof(void *));
+
+  argn = 0;
+
+  /* Copy the caller's structure return address to that the closure
+     returns the data directly to the caller.  */
+  if (cif->flags == FFI_TYPE_STRUCT)
+    {
+      rvalue = (void *) gpr[0];
+      argn = 1;
+    }
+
+  i = 0;
+  avn = cif->nargs;
+  arg_types = cif->arg_types;
+
+  /* Grab the addresses of the arguments from the stack frame.  */
+  while (i < avn)
+    {
+      /* Assume big-endian.  FIXME */
+      argn += ALIGN(arg_types[i]->size, SIZEOF_ARG) / SIZEOF_ARG;
+
+#ifdef SPARC64
+      if (i < 6 && (arg_types[i]->type == FFI_TYPE_FLOAT
+		 || arg_types[i]->type == FFI_TYPE_DOUBLE
+#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
+		 || arg_types[i]->type == FFI_TYPE_LONGDOUBLE
+#endif
+		))
+        avalue[i] = ((char *) &fpr[argn]) - arg_types[i]->size;
+      else
+#endif
+        avalue[i] = ((char *) &gpr[argn]) - arg_types[i]->size;
+      i++;
+    }
+
+  /* Invoke the closure.  */
+  (closure->fun) (cif, rvalue, avalue, closure->user_data);
+
+  /* Tell ffi_closure_sparc how to perform return type promotions.  */
+  return cif->rtype->type;
 }
Index: src/sparc/v8.S
===================================================================
RCS file: /cvs/gcc/gcc/libffi/src/sparc/v8.S,v
retrieving revision 1.6
diff -u -p -r1.6 v8.S
--- src/sparc/v8.S	28 Apr 2002 19:57:42 -0000	1.6
+++ src/sparc/v8.S	17 Jul 2002 04:56:46 -0000
@@ -94,6 +94,97 @@ longlong:
 .ffi_call_V8_end:
 	.size	ffi_call_V8,.ffi_call_V8_end-ffi_call_V8

+
+#define	STACKFRAME	104	/* 16*4 register window +
+				   1*4 struct return +
+				   6*4 args backing store +
+				   3*4 locals */
+
+/* ffi_closure_v8(...)
+
+   Receives the closure argument in %g2.   */
+
+	.text
+	.align 8
+	.globl ffi_closure_v8
+
+ffi_closure_v8:
+	.register	%g2, #scratch
+.LLFB2:
+	save	%sp, -STACKFRAME, %sp
+.LLCFI1:
+
+	! Store all of the potential argument registers in va_list format.
+	st	%i0, [%fp+68+0]
+	st	%i1, [%fp+68+4]
+	st	%i2, [%fp+68+8]
+	st	%i3, [%fp+68+12]
+	st	%i4, [%fp+68+16]
+	st	%i5, [%fp+68+20]
+
+	! Call ffi_closure_sparc_inner to do the bulk of the work.
+	mov	%g2, %o0
+	add	%fp, -8, %o1
+	add	%fp,  68, %o2
+	call	ffi_closure_sparc_inner
+	 mov	0, %o3
+
+	! Load up the return value in the proper type.
+	cmp	%o0, FFI_TYPE_VOID
+	be	done1
+
+	cmp	%o0, FFI_TYPE_INT
+	be,a	done1
+	 ld	[%fp-8], %i0
+
+	cmp	%o0, FFI_TYPE_POINTER
+	be,a	done1
+	 ld	[%fp-8], %i0
+
+	cmp	%o0, FFI_TYPE_FLOAT
+	be,a	done1
+	 ld	[%fp-8], %f0
+
+	cmp	%o0, FFI_TYPE_DOUBLE
+	be,a	done1
+	 ldd	[%fp-8], %f0
+
+	cmp	%o0, FFI_TYPE_UINT8
+	be,a	done1
+	 ldub	[%fp-8], %i0
+
+	cmp	%o0, FFI_TYPE_SINT8
+	be,a	done1
+	 ldsb	[%fp-8], %i0
+
+	cmp	%o0, FFI_TYPE_UINT16
+	be,a	done1
+	 lduh	[%fp-8], %i0
+
+	cmp	%o0, FFI_TYPE_SINT16
+	be,a	done1
+	 ldsh	[%fp-8], %i0
+
+	cmp	%o0, FFI_TYPE_UINT32
+	be,a	done1
+	 ld	[%fp-8], %i0
+
+	cmp	%o0, FFI_TYPE_SINT32
+	be,a	done1
+	 ld	[%fp-8], %i0
+
+	! FFI_TYPE_UINT64 | FFI_TYPE_SINT64
+	ld	[%fp-8], %i0
+	ld	[%fp-4], %i1
+
+done1:
+	ret
+	 restore
+.LLFE2:
+
+.ffi_closure_v8_end:
+	.size	ffi_closure_v8,.ffi_closure_v8_end-ffi_closure_v8
+
 #ifdef SPARC64
 #define WS 8
 #define nword	xword
@@ -148,3 +239,26 @@ longlong:
 	.byte	0x1f	! uleb128 0x1f
 	.align	WS
 .LLEFDE1:
+.LLSFDE2:
+	.uaword	.LLEFDE2-.LLASFDE2	! FDE Length
+.LLASFDE2:
+	.uaword	.LLASFDE2-.LLframe1	! FDE CIE offset
+#ifdef HAVE_AS_SPARC_UA_PCREL
+	.uaword	%r_disp32(.LLFB2)
+	.uaword	.LLFE2-.LLFB2	! FDE address range
+#else
+	.align	WS
+	.nword	.LLFB2
+	.uanword .LLFE2-.LLFB2	! FDE address range
+#endif
+	.byte	0x0	! uleb128 0x0; Augmentation size
+	.byte	0x4	! DW_CFA_advance_loc4
+	.uaword	.LLCFI1-.LLFB2
+	.byte	0xd	! DW_CFA_def_cfa_register
+	.byte	0x1e	! uleb128 0x1e
+	.byte	0x2d	! DW_CFA_GNU_window_save
+	.byte	0x9	! DW_CFA_register
+	.byte	0xf	! uleb128 0xf
+	.byte	0x1f	! uleb128 0x1f
+	.align	WS
+.LLEFDE2:
Index: src/sparc/v9.S
===================================================================
RCS file: /cvs/gcc/gcc/libffi/src/sparc/v9.S,v
retrieving revision 1.4
diff -u -p -r1.4 v9.S
--- src/sparc/v9.S	28 Apr 2002 19:57:42 -0000	1.4
+++ src/sparc/v9.S	17 Jul 2002 04:56:46 -0000
@@ -99,7 +99,7 @@ _ffi_call_V9:
 	cmp	%i3, FFI_TYPE_STRUCT
 	be,pn	%icc, dostruct

-	 cmp	%i3, FFI_TYPE_LONGDOUBLE
+	cmp	%i3, FFI_TYPE_LONGDOUBLE
 	bne,pt	%icc, done
 	 nop
 	std	%f0, [%i4+0]
@@ -125,6 +125,116 @@ dostruct:
 .ffi_call_V9_end:
 	.size	ffi_call_V9,.ffi_call_V9_end-ffi_call_V9

+
+#define	STACKFRAME	 240	/* 16*8 register window +
+				   6*8 args backing store +
+				   8*8 locals */
+#define	FP		%fp+STACK_BIAS
+
+/* ffi_closure_v9(...)
+
+   Receives the closure argument in %g1.   */
+
+	.text
+	.align 8
+	.globl ffi_closure_v9
+
+ffi_closure_v9:
+.LLFB2:
+	save	%sp, -STACKFRAME, %sp
+.LLCFI1:
+
+	! Store all of the potential argument registers in va_list format.
+	stx	%i0, [FP+128+0]
+	stx	%i1, [FP+128+8]
+	stx	%i2, [FP+128+16]
+	stx	%i3, [FP+128+24]
+	stx	%i4, [FP+128+32]
+	stx	%i5, [FP+128+40]
+
+	! Store possible floating point argument registers too.
+	std	%f0, [FP-48]
+	std	%f2, [FP-40]
+	std	%f4, [FP-32]
+	std	%f6, [FP-24]
+	std	%f8, [FP-16]
+	std	%f10, [FP-8]
+
+	! Call ffi_closure_sparc_inner to do the bulk of the work.
+	mov	%g1, %o0
+	add	%fp, STACK_BIAS-64, %o1
+	add	%fp, STACK_BIAS+128, %o2
+	call	ffi_closure_sparc_inner
+	 add	%fp, STACK_BIAS-48, %o3
+
+	! Load up the return value in the proper type.
+	cmp	%o0, FFI_TYPE_VOID
+	be,pn	%icc, done1
+
+	cmp	%o0, FFI_TYPE_INT
+	be,a,pn	%icc, done1
+	 ldsw	[FP-64], %i0
+
+	cmp	%o0, FFI_TYPE_FLOAT
+	be,a,pn	%icc, done1
+	 ld	[FP-64], %f0
+
+	cmp	%o0, FFI_TYPE_DOUBLE
+	be,a,pn	%icc, done1
+	 ldd	[FP-64], %f0
+
+	cmp	%o0, FFI_TYPE_UINT8
+	be,a,pn	%icc, done1
+	 ldub	[FP-64], %i0
+
+	cmp	%o0, FFI_TYPE_SINT8
+	be,a,pn	%icc, done1
+	 ldsb	[FP-64], %i0
+
+	cmp	%o0, FFI_TYPE_UINT16
+	be,a,pn	%icc, done1
+	 lduh	[FP-64], %i0
+
+	cmp	%o0, FFI_TYPE_SINT16
+	be,a,pn	%icc, done1
+	 ldsh	[FP-64], %i0
+
+	cmp	%o0, FFI_TYPE_UINT32
+	be,a,pn	%icc, done1
+	 lduw	[FP-64], %i0
+
+	cmp	%o0, FFI_TYPE_SINT32
+	be,a,pn	%icc, done1
+	 ldsw	[FP-64], %i0
+
+	cmp	%o0, FFI_TYPE_LONGDOUBLE
+	be,a,pn	%icc, longdouble1
+	 ldd	[FP-64], %f0
+
+	cmp	%o0, FFI_TYPE_STRUCT
+	be,pn	%icc, struct1
+
+	! FFI_TYPE_UINT64 | FFI_TYPE_SINT64 | FFI_TYPE_POINTER
+	ldx	[FP-64], %i0
+
+done1:
+	ret
+	 restore
+
+struct1:
+	ldx [FP-56], %i2
+	ret
+	 restore
+
+longdouble1:
+	ldd	[FP-56], %f2
+	ret
+	 restore
+.LLFE2:
+
+.ffi_closure_v9_end:
+	.size	ffi_closure_v9,.ffi_closure_v9_end-ffi_closure_v9
+
 	.section	".eh_frame",#alloc,#write
 .LLframe1:
 	.uaword	.LLECIE1-.LLSCIE1	! Length of Common Information Entry
@@ -169,5 +279,27 @@ dostruct:
 	.byte	0x1f	! uleb128 0x1f
 	.align 8
 .LLEFDE1:
-
+.LLSFDE2:
+	.uaword	.LLEFDE2-.LLASFDE2	! FDE Length
+.LLASFDE2:
+	.uaword	.LLASFDE2-.LLframe1	! FDE CIE offset
+#ifdef HAVE_AS_SPARC_UA_PCREL
+	.uaword	%r_disp32(.LLFB2)
+	.uaword	.LLFE2-.LLFB2		! FDE address range
+#else
+	.align 8
+	.xword	.LLFB2
+	.uaxword	.LLFE2-.LLFB2	! FDE address range
+#endif
+	.byte	0x0	! uleb128 0x0; Augmentation size
+	.byte	0x4	! DW_CFA_advance_loc4
+	.uaword	.LLCFI1-.LLFB2
+	.byte	0xd	! DW_CFA_def_cfa_register
+	.byte	0x1e	! uleb128 0x1e
+	.byte	0x2d	! DW_CFA_GNU_window_save
+	.byte	0x9	! DW_CFA_register
+	.byte	0xf	! uleb128 0xf
+	.byte	0x1f	! uleb128 0x1f
+	.align 8
+.LLEFDE2:
 #endif




More information about the Java-patches mailing list