This is the mail archive of the java@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]

Re: JNI in GCJ 3.2 for Win32


Ranjit Mathew wrote:
I tried it out for the case of just adding the extra
argument size, but it failed with an "internal error:
Segmentation fault" :-(

I'll try it afresh tomorrow.
Mea Culpa! There were a couple of really silly bugs
in my patch. FWIW, they were:

a. using size_of_args( ) instead of int_size_of_args( ) - as
Tom had suggested in the first place. Sorry about that!
(size_of_args( ) returns a "tree"!)

b. incorrect function type attribute specification for "stdcall".
In GCC parlance, a function type attribute must be a TREE_LIST
with TREE_PURPOSE set to the identifier for the attribute
and TREE_VALUE set to the arguments for the attribute
(NULL_TREE for stdcall) - I had just passed an identifier
node instead. Classic case of not having RTFM!

These out of the way, I'm happy to report that now even
native Java code works with JNI on Windows for both
static and member methods.

As for the issues raised by Tom:

1. I used unsigned short simply because I didn't expect native
functions to take more than 65536 bytes as arguments. Maybe
I should use normal integers instead.

2. I used the __MINGW32__ and __CYGWIN__ definitions simply
because I didn't know how to switch based on the target.
None of xm-*ming*.h or *ming*.h in "gcc/config/i386"
contained any useful #define.

3. I am a bit confused about GCC coding conventions when code
spills over a single line - another case for RTFM. Sorry.
Hopefully this time it is better.

BTW, thank you very much, Tom, for patiently guiding me
through this.

Finally, here're the relevant changes to the compiler and the
interpreter - changing it to the form Tom mentioned and
migrating it to GCJ 3.3 is left as an exercise for the
reader ;-) :
---------------------------- 8< --------------------------------
--- jni.cc.orig 2002-11-08 08:28:50.000000000 +0530
+++ jni.cc 2002-11-12 07:40:26.000000000 +0530
@@ -11,4 +11,5 @@
#include <config.h>

+#include <stdio.h>
#include <stddef.h>
#include <string.h>
@@ -1982,7 +1983,7 @@
extern "C" void *
_Jv_LookupJNIMethod (jclass klass, _Jv_Utf8Const *name,
- _Jv_Utf8Const *signature)
+ _Jv_Utf8Const *signature, _Jv_ushort args_size)
{
- char buf[10 + 6 * (name->length + signature->length)];
+ char buf[10 + 6 * (name->length + signature->length) + 6];
int long_start;
void *function;
@@ -2007,4 +2008,18 @@
char c = buf[long_start];
buf[long_start] = '\0';
+
+#ifdef WIN32
+ // On Win32, we use the stdcall calling convention (ref. JNICALL in jni.h).
+ //
+ // The stdcall convention puts a '@xx' at the end of a function that
+ // takes 'xx' number of bytes as arguments.
+
+ char asz_buf[7]; /* '@' + '65535' (16-bit ushort max.) + '\0' */
+ sprintf( asz_buf, "@%hu", args_size);
+ strcat( buf, asz_buf);
+#else
+ args_size; /* Dummy statement to avoid unused parameter warning */
+#endif /* ! WIN32 */
+
function = _Jv_FindSymbolInExecutable (buf);
if (function == NULL)
@@ -2046,7 +2061,15 @@
JvSynchronize sync (global_ref_table);
if (_this->function == NULL)
- _this->function = _Jv_LookupJNIMethod (_this->defining_class,
- _this->self->name,
- _this->self->signature);
+ {
+ unsigned short args_size = sizeof (JNIEnv *) + _this->args_raw_size;
+
+ if (_this->self->accflags & java::lang::reflect::Modifier::STATIC)
+ args_size += sizeof (_this->defining_class);
+
+ _this->function = _Jv_LookupJNIMethod (_this->defining_class,
+ _this->self->name,
+ _this->self->signature,
+ args_size);
+ }
}

--- resolve.cc.orig 2002-11-08 07:30:42.000000000 +0530
+++ resolve.cc 2002-11-10 18:33:57.000000000 +0530
@@ -1153,5 +1153,12 @@
arg_count * sizeof (ffi_type *));

- if (ffi_prep_cif (&jni_cif, FFI_DEFAULT_ABI,
+// NOTE: This must be consistent with the definition of JNICALL in jni.h
+#ifdef WIN32
+#define FFI_JNI_ABI FFI_STDCALL
+#else
+#define FFI_JNI_ABI FFI_DEFAULT_ABI
+#endif
+
+ if (ffi_prep_cif (&jni_cif, FFI_JNI_ABI,
extra_args + arg_count, rtype,
jni_arg_types) != FFI_OK)

--- decl.c.orig 2002-11-11 03:02:05.000000000 +0530
+++ decl.c 2002-11-11 03:40:08.000000000 +0530
@@ -850,5 +850,6 @@
t = tree_cons (NULL_TREE, object_ptr_type_node,
tree_cons (NULL_TREE, ptr_type_node,
- tree_cons (NULL_TREE, ptr_type_node, endlink)));
+ tree_cons (NULL_TREE, ptr_type_node,
+ tree_cons (NULL_TREE, unsigned_short_type_node, endlink))));
soft_lookupjnimethod_node
= builtin_function ("_Jv_LookupJNIMethod",
--- expr.c.orig 2002-11-11 03:02:00.000000000 +0530
+++ expr.c 2002-11-12 07:33:23.000000000 +0530
@@ -2187,4 +2187,6 @@
tree meth_var;

+ unsigned short args_size = 0;
+
tree klass = DECL_CONTEXT (method);
int from_class = ! CLASS_FROM_SOURCE_P (klass);
@@ -2248,5 +2250,8 @@
args = NULL_TREE;
for (tem = method_args; tem != NULL_TREE; tem = TREE_CHAIN (tem))
- args = tree_cons (NULL_TREE, tem, args);
+ {
+ args_size += int_size_in_bytes (TREE_TYPE(tem));
+ args = tree_cons (NULL_TREE, tem, args);
+ }
args = nreverse (args);
arg_types = TYPE_ARG_TYPES (TREE_TYPE (method));
@@ -2257,4 +2262,5 @@
if (METHOD_STATIC (method))
{
+ args_size += int_size_in_bytes (TREE_TYPE(klass));
args = tree_cons (NULL_TREE, klass, args);
arg_types = tree_cons (NULL_TREE, object_ptr_type_node, arg_types);
@@ -2262,4 +2268,5 @@

/* The JNIEnv structure is the first argument to the JNI function. */
+ args_size += int_size_in_bytes (TREE_TYPE(env_var));
args = tree_cons (NULL_TREE, env_var, args);
arg_types = tree_cons (NULL_TREE, ptr_type_node, arg_types);
@@ -2268,18 +2275,27 @@
function pointer. _Jv_LookupJNIMethod will throw the appropriate
exception if this function is not found at runtime. */
+ tem = build_tree_list (NULL_TREE, build_int_2 (args_size, 0));
method_sig = build_java_signature (TREE_TYPE (method));
- lookup_arg =
- build_tree_list (NULL_TREE,
- build_utf8_ref (unmangle_classname
- (IDENTIFIER_POINTER (method_sig),
- IDENTIFIER_LENGTH (method_sig))));
+ lookup_arg = tree_cons (NULL_TREE,
+ build_utf8_ref (unmangle_classname
+ (IDENTIFIER_POINTER (method_sig),
+ IDENTIFIER_LENGTH (method_sig))),
+ tem);
tem = DECL_NAME (method);
lookup_arg
= tree_cons (NULL_TREE, klass,
tree_cons (NULL_TREE, build_utf8_ref (tem), lookup_arg));
+
+ tem = build_function_type (TREE_TYPE (TREE_TYPE (method)), arg_types);
+
+ #if defined (__MINGW32__) || defined (__CYGWIN__)
+ /* JNI methods on Win32 are invoked using the stdcall convention */
+ tem = build_type_attribute_variant (tem,
+ build_tree_list
+ (get_identifier ("stdcall"),
+ NULL));
+ #endif

- jni_func_type
- = build_pointer_type (build_function_type (TREE_TYPE (TREE_TYPE (method)),
- arg_types));
+ jni_func_type = build_pointer_type (tem);

jnifunc = build (COND_EXPR, ptr_type_node,
---------------------------- 8< --------------------------------

Sincerely Yours,
Ranjit.

--
Ranjit Mathew Email: rmathew AT hotmail DOT com

Bangalore, INDIA. Web: http://ranjitmathew.tripod.com/




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