This is the mail archive of the
java-patches@gcc.gnu.org
mailing list for the Java project.
[PATCH] Fix libffi for 64-bit big-endian platforms
- From: "Ulrich Weigand" <Ulrich dot Weigand at de dot ibm dot com>
- To: java-patches at gcc dot gnu dot org
- Cc: gcc-patches at gcc dot gnu dot org, jsturm at one-point dot com, green at redhat dot com
- Date: Wed, 2 Oct 2002 19:07:31 +0200
- Subject: [PATCH] Fix libffi for 64-bit big-endian platforms
- Sensitivity:
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