This is the mail archive of the java-patches@gcc.gnu.org mailing list for the Java project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[PATCH] Fix libffi for 64-bit big-endian platforms


Hello,

looking at the patches and discussions pointed out by Jeff Sturm,
and thinking some more about the problem, I've come to this patch
which I propose as (at least short-term) solution to get gij running
on s390x (and s390).

The core of the problem is that the libffi API is not quite
clearly specified; in particular the question is how the
various void pointers passed as rvalue and avalues[i] are to
be interpreted.

The three API variants, "cooked", raw, and Java-raw, have
basically different expectations.  The first uses pointers
to the actual data types as specified in the cif, the second
operates with the ffi_raw union, while the third wants to
use the _Jv_word union from libgcj unchanged.  So, in an
ideal world we would expect this API:

             avalues[i]        rvalue
"cooked"     type *            type *
raw          ffi_raw *         ffi_raw *
Java raw     _Jv_word *        _Jv_word *

However, this is not what is currently implemented.  That
looks more like this:

             avalues[i]        rvalue
"cooked"     type *            ffi_raw *
raw          ffi_raw *         ffi_raw *
Java raw     ffi_raw *         ffi_raw *

Note that the "cooked" API does not interpret rvalue as
a pointer to the correct type, but to a promoted type
(more or less like ffi_raw).  The Java-raw API simply
uses ffi_raw, and expects that this is compatible with
the _Jv_word type (which it actually *is* on all platforms
except big-endian 64-bit ones).

With the following patch, the situation would be changed to:

             avalues[i]        rvalue
"cooked"     type *            ffi_raw *
raw          ffi_raw *         ffi_raw *
Java raw     _Jv_word *        _Jv_word *

This still doesn't change the "cooked" rvalue interpretation
(because this would mean to change all platform backends and
all callers as well), but it fixes the Java-raw case.

This patch has the advantage that it:
 - only touches libffi (and only in java_raw_api.c)
 - does not change the behaviour of libffi in any way
   *unless* on 64-bit big-endian platforms
and therefore cannot possibly break either any existing
port of libffi (there are no working ports to 64-bit
big-endian platforms) or any current user of libffi.


Also, with this patch, and a (separately posted) patch to
actually enable gij for s390* targets (and with a fixed
glibc installed :-/), I can successfully complete a libjava
regression test on s390-ibm-linux and s390x-ibm-linux, with
only failures that are not platform specific as far as I can
see (with the possible exception of err10 on s390x-ibm-linux,
but I've seen this elsewhere as well IIRC).

s390-ibm-linux test results:
FAIL: PR1343 compilation from bytecode
FAIL: PR1343 -O compilation from bytecode
FAIL: Array_3 -O execution - source compiled test
FAIL: TestProxy execution - source compiled test
FAIL: TestProxy execution - gij test
FAIL: TestProxy execution - bytecode->native test
FAIL: TestProxy -O execution - source compiled test
FAIL: TestProxy execution - gij test
FAIL: TestProxy -O execution - bytecode->native test
FAIL: utf8concat execution - source compiled test
FAIL: utf8concat execution - gij test
FAIL: utf8concat execution - bytecode->native test
FAIL: utf8concat -O execution - source compiled test
FAIL: utf8concat execution - gij test
FAIL: utf8concat -O execution - bytecode->native test

s390x-ibm-linux test results:
FAIL: PR1343 compilation from bytecode
FAIL: PR1343 -O compilation from bytecode
FAIL: Array_3 -O execution - source compiled test
FAIL: TestProxy execution - source compiled test
FAIL: TestProxy execution - gij test
FAIL: TestProxy execution - bytecode->native test
FAIL: TestProxy -O execution - source compiled test
FAIL: TestProxy execution - gij test
FAIL: TestProxy -O execution - bytecode->native test
FAIL: err10 output - gij test
FAIL: err10 output - gij test
FAIL: utf8concat execution - source compiled test
FAIL: utf8concat execution - gij test
FAIL: utf8concat execution - bytecode->native test
FAIL: utf8concat -O execution - source compiled test
FAIL: utf8concat execution - gij test
FAIL: utf8concat -O execution - bytecode->native test


Note that the ffi_java_raw_to_ptrarray and ffi_java_ptrarray_to_raw
hunks of the following patch are due to Jeff Sturm (from his sparc64
patch).

OK to apply?


ChangeLog:

      * src/java_raw_api.c (ffi_java_raw_to_ptrarray): Interpret
      raw data as _Jv_word values, not ffi_raw.
      (ffi_java_ptrarray_to_raw): Likewise.
      (ffi_java_rvalue_to_raw): New function.
      (ffi_java_raw_call): Call it.
      (ffi_java_raw_to_rvalue): New function.
      (ffi_java_translate_args): Call it.
      * src/ffitest.c (closure_test_fn): Interpret return value
      as ffi_arg, not int.
      * src/s390/ffi.c (ffi_prep_cif_machdep): Add missing
      FFI_TYPE_POINTER case.
      (ffi_closure_helper_SYSV): Likewise.  Also, assume return
      values extended to word size.


Index: libffi/src/ffitest.c
===================================================================
RCS file: /cvs/gcc/gcc/libffi/src/ffitest.c,v
retrieving revision 1.7
diff -c -p -r1.7 ffitest.c
*** libffi/src/ffitest.c      18 Jul 2002 23:08:30 -0000    1.7
--- libffi/src/ffitest.c      2 Oct 2002 15:46:02 -0000
*************** static test_structure_9 struct9 (test_st
*** 262,268 ****
  static void
  closure_test_fn(ffi_cif* cif,void* resp,void** args, void* userdata)
  {
!   *(int*)resp = *(int*)args[0] + (int)(*(float*)args[1]) + (int)(long)userdata;
  }

  typedef int (*closure_test_type)(int, float);
--- 262,268 ----
  static void
  closure_test_fn(ffi_cif* cif,void* resp,void** args, void* userdata)
  {
!   *(ffi_arg*)resp = *(int*)args[0] + (int)(*(float*)args[1]) + (int)(long)userdata;
  }

  typedef int (*closure_test_type)(int, float);
Index: libffi/src/java_raw_api.c
===================================================================
RCS file: /cvs/gcc/gcc/libffi/src/java_raw_api.c,v
retrieving revision 1.2
diff -c -p -r1.2 java_raw_api.c
*** libffi/src/java_raw_api.c 8 Apr 2002 23:59:13 -0000     1.2
--- libffi/src/java_raw_api.c 2 Oct 2002 15:46:02 -0000
*************** ffi_java_raw_to_ptrarray (ffi_cif *cif,
*** 81,101 ****
      {
      case FFI_TYPE_UINT8:
      case FFI_TYPE_SINT8:
!       *args = (void*) ((char*)(raw++) + SIZEOF_ARG - 1);
        break;

      case FFI_TYPE_UINT16:
      case FFI_TYPE_SINT16:
!       *args = (void*) ((char*)(raw++) + SIZEOF_ARG - 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:
--- 81,94 ----
      {
      case FFI_TYPE_UINT8:
      case FFI_TYPE_SINT8:
!       *args = (void*) ((char*)(raw++) + 3);
        break;

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

  #if SIZEOF_ARG == 8
      case FFI_TYPE_UINT64:
      case FFI_TYPE_SINT64:
*************** ffi_java_ptrarray_to_raw (ffi_cif *cif,
*** 157,187 ****
        switch ((*tp)->type)
      {
      case FFI_TYPE_UINT8:
        (raw++)->uint = *(UINT8*) (*args);
        break;

      case FFI_TYPE_SINT8:
        (raw++)->sint = *(SINT8*) (*args);
        break;

      case FFI_TYPE_UINT16:
        (raw++)->uint = *(UINT16*) (*args);
        break;

      case FFI_TYPE_SINT16:
        (raw++)->sint = *(SINT16*) (*args);
        break;

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

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

--- 150,203 ----
        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;

      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);
  #endif
!       break;
!
!     case FFI_TYPE_FLOAT:
        (raw++)->flt = *(FLOAT32*) (*args);
        break;

*************** ffi_java_ptrarray_to_raw (ffi_cif *cif,
*** 211,216 ****
--- 227,281 ----

  #if !FFI_NATIVE_RAW_API

+ static void
+ ffi_java_rvalue_to_raw (ffi_cif *cif, void *rvalue)
+ {
+ #if WORDS_BIGENDIAN && SIZEOF_ARG == 8
+   switch (cif->rtype->type)
+     {
+     case FFI_TYPE_UINT8:
+     case FFI_TYPE_UINT16:
+     case FFI_TYPE_UINT32:
+       *(UINT64 *)rvalue <<= 32;
+       break;
+
+     case FFI_TYPE_SINT8:
+     case FFI_TYPE_SINT16:
+     case FFI_TYPE_SINT32:
+     case FFI_TYPE_INT:
+       *(SINT64 *)rvalue <<= 32;
+       break;
+
+     default:
+       break;
+     }
+ #endif
+ }
+
+ static void
+ ffi_java_raw_to_rvalue (ffi_cif *cif, void *rvalue)
+ {
+ #if WORDS_BIGENDIAN && SIZEOF_ARG == 8
+   switch (cif->rtype->type)
+     {
+     case FFI_TYPE_UINT8:
+     case FFI_TYPE_UINT16:
+     case FFI_TYPE_UINT32:
+       *(UINT64 *)rvalue >>= 32;
+       break;
+
+     case FFI_TYPE_SINT8:
+     case FFI_TYPE_SINT16:
+     case FFI_TYPE_SINT32:
+     case FFI_TYPE_INT:
+       *(SINT64 *)rvalue >>= 32;
+       break;
+
+     default:
+       break;
+     }
+ #endif
+ }

  /* This is a generic definition of ffi_raw_call, to be used if the
   * native system does not provide a machine-specific implementation.
*************** void ffi_java_raw_call (/*@dependent@*/
*** 227,232 ****
--- 292,298 ----
    void **avalue = (void**) alloca (cif->nargs * sizeof (void*));
    ffi_java_raw_to_ptrarray (cif, raw, avalue);
    ffi_call (cif, fn, rvalue, avalue);
+   ffi_java_rvalue_to_raw (cif, rvalue);
  }

  #if FFI_CLOSURES            /* base system provides closures */
*************** ffi_java_translate_args (ffi_cif *cif, v
*** 240,245 ****
--- 306,312 ----

    ffi_java_ptrarray_to_raw (cif, avalue, raw);
    (*cl->fun) (cif, rvalue, raw, cl->user_data);
+   ffi_java_raw_to_rvalue (cif, rvalue);
  }

  /* Again, here is the generic version of ffi_prep_raw_closure, which
Index: libffi/src/s390/ffi.c
===================================================================
RCS file: /cvs/gcc/gcc/libffi/src/s390/ffi.c,v
retrieving revision 1.2
diff -c -p -r1.2 ffi.c
*** libffi/src/s390/ffi.c     30 Sep 2002 11:59:42 -0000    1.2
--- libffi/src/s390/ffi.c     2 Oct 2002 15:46:03 -0000
*************** ffi_prep_cif_machdep(ffi_cif *cif)
*** 369,374 ****
--- 369,375 ----
      cif->flags = FFI390_RET_INT64;
      break;

+       case FFI_TYPE_POINTER:
        case FFI_TYPE_INT:
        case FFI_TYPE_UINT32:
        case FFI_TYPE_SINT32:
*************** ffi_closure_helper_SYSV (ffi_closure *cl
*** 682,710 ****
  #endif
      break;

        case FFI_TYPE_UINT32:
!     p_gpr[0] = *(unsigned int *) rvalue;
      break;

        case FFI_TYPE_INT:
        case FFI_TYPE_SINT32:
-     p_gpr[0] = *(signed int *) rvalue;
-     break;
-
-       case FFI_TYPE_UINT16:
-     p_gpr[0] = *(unsigned short *) rvalue;
-     break;
-
        case FFI_TYPE_SINT16:
-     p_gpr[0] = *(signed short *) rvalue;
-     break;
-
-       case FFI_TYPE_UINT8:
-     p_gpr[0] = *(unsigned char *) rvalue;
-     break;
-
        case FFI_TYPE_SINT8:
!     p_gpr[0] = *(signed char *) rvalue;
      break;

        default:
--- 683,700 ----
  #endif
      break;

+       case FFI_TYPE_POINTER:
        case FFI_TYPE_UINT32:
!       case FFI_TYPE_UINT16:
!       case FFI_TYPE_UINT8:
!     p_gpr[0] = *(unsigned long *) rvalue;
      break;

        case FFI_TYPE_INT:
        case FFI_TYPE_SINT32:
        case FFI_TYPE_SINT16:
        case FFI_TYPE_SINT8:
!     p_gpr[0] = *(signed long *) rvalue;
      break;

        default:

Mit freundlichen Gruessen / Best Regards

Ulrich Weigand

--
  Dr. Ulrich Weigand
  Linux for S/390 Design & Development
  IBM Deutschland Entwicklung GmbH, Schoenaicher Str. 220, 71032 Boeblingen
  Phone: +49-7031/16-3727   ---   Email: Ulrich.Weigand@de.ibm.com


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]