Commit 7145d9fe by Tom Tromey Committed by Tom Tromey

class.c (add_method_1): Set both DECL_EXTERNAL and METHOD_NATIVE on native function.

	* class.c (add_method_1): Set both DECL_EXTERNAL and METHOD_NATIVE
	on native function.
	* jcf-parse.c (parse_class_file): Call build_jni_stub for native
	JNI methods.
	* expr.c (build_jni_stub): New function.
	* lang-specs.h: -fjni and -femit-class-file are incompatible.
	* parse.c: Rebuilt.
	* parse.y (java_complete_expand_methods): Expand a native method
	and call build_jni_stub if -fjni given.
	* lang-options.h: Document -fjni.
	* lang.c (flag_jni): New global.
	(lang_f_options): Added `jni' entry.
	* java-tree.h (soft_lookupjnimethod_node,
	soft_getjnienvnewframe_node, soft_jnipopsystemframe_node):
	Declare.
	(flag_jni): Declare.
	(build_jni_stub): Declare.
	(struct lang_decl): Added `native' flag.
	(METHOD_NATIVE): Redefined to use `native' field of lang specific
	structure.
	* decl.c (soft_lookupjnimethod_node, soft_getjnienvnewframe_node,
	soft_jnipopsystemframe_node): New globals.
	(init_decl_processing): Set them.  _Jv_InitClass only takes one
	argument.

	* java-tree.def: Put into `C' mode.

From-SVN: r33615
parent 09fa0705
2000-04-19 Tom Tromey <tromey@cygnus.com>
* class.c (add_method_1): Set both DECL_EXTERNAL and METHOD_NATIVE
on native function.
* jcf-parse.c (parse_class_file): Call build_jni_stub for native
JNI methods.
* expr.c (build_jni_stub): New function.
* lang-specs.h: -fjni and -femit-class-file are incompatible.
* parse.c: Rebuilt.
* parse.y (java_complete_expand_methods): Expand a native method
and call build_jni_stub if -fjni given.
* lang-options.h: Document -fjni.
* lang.c (flag_jni): New global.
(lang_f_options): Added `jni' entry.
* java-tree.h (soft_lookupjnimethod_node,
soft_getjnienvnewframe_node, soft_jnipopsystemframe_node):
Declare.
(flag_jni): Declare.
(build_jni_stub): Declare.
(struct lang_decl): Added `native' flag.
(METHOD_NATIVE): Redefined to use `native' field of lang specific
structure.
* decl.c (soft_lookupjnimethod_node, soft_getjnienvnewframe_node,
soft_jnipopsystemframe_node): New globals.
(init_decl_processing): Set them. _Jv_InitClass only takes one
argument.
* java-tree.def: Put into `C' mode.
2000-04-27 Tom Tromey <tromey@cygnus.com>
Fix for PR gcj/2:
......
......@@ -644,7 +644,11 @@ add_method_1 (handle_class, access_flags, name, function_type)
if (access_flags & ACC_PROTECTED) METHOD_PROTECTED (fndecl) = 1;
if (access_flags & ACC_PRIVATE)
METHOD_PRIVATE (fndecl) = DECL_INLINE (fndecl) = 1;
if (access_flags & ACC_NATIVE) METHOD_NATIVE (fndecl) = 1;
if (access_flags & ACC_NATIVE)
{
METHOD_NATIVE (fndecl) = 1;
DECL_EXTERNAL (fndecl) = 1;
}
if (access_flags & ACC_STATIC)
METHOD_STATIC (fndecl) = DECL_INLINE (fndecl) = 1;
if (access_flags & ACC_FINAL)
......
......@@ -381,6 +381,9 @@ tree soft_checkarraystore_node;
tree soft_monitorenter_node;
tree soft_monitorexit_node;
tree soft_lookupinterfacemethod_node;
tree soft_lookupjnimethod_node;
tree soft_getjnienvnewframe_node;
tree soft_jnipopsystemframe_node;
tree soft_fmod_node;
tree soft_exceptioninfo_call_node;
tree soft_idiv_node;
......@@ -753,12 +756,13 @@ init_decl_processing ()
build_function_type (ptr_type_node, t),
0, NOT_BUILT_IN, NULL_PTR);
DECL_IS_MALLOC (alloc_object_node) = 1;
t = tree_cons (NULL_TREE, ptr_type_node, endlink);
soft_initclass_node = builtin_function ("_Jv_InitClass",
build_function_type (void_type_node,
t),
0, NOT_BUILT_IN,
NULL_PTR);
t = tree_cons (NULL_TREE, ptr_type_node, endlink);
throw_node[0] = builtin_function ("_Jv_Throw",
build_function_type (ptr_type_node, t),
0, NOT_BUILT_IN, NULL_PTR);
......@@ -848,6 +852,24 @@ init_decl_processing ()
= builtin_function ("_Jv_LookupInterfaceMethodIdx",
build_function_type (ptr_type_node, t),
0, NOT_BUILT_IN, NULL_PTR);
t = tree_cons (NULL_TREE, object_ptr_type_node,
tree_cons (NULL_TREE, ptr_type_node,
tree_cons (NULL_TREE, ptr_type_node, endlink)));
soft_lookupjnimethod_node
= builtin_function ("_Jv_LookupJNIMethod",
build_function_type (ptr_type_node, t),
0, NOT_BUILT_IN, NULL_PTR);
t = tree_cons (NULL_TREE, ptr_type_node, endlink);
soft_getjnienvnewframe_node
= builtin_function ("_Jv_GetJNIEnvNewFrame",
build_function_type (ptr_type_node, t),
0, NOT_BUILT_IN, NULL_PTR);
soft_jnipopsystemframe_node
= builtin_function ("_Jv_JNI_PopSystemFrame",
build_function_type (ptr_type_node, t),
0, NOT_BUILT_IN, NULL_PTR);
t = tree_cons (NULL_TREE, double_type_node,
tree_cons (NULL_TREE, double_type_node, endlink));
soft_fmod_node
......@@ -1726,7 +1748,7 @@ complete_start_java_method (fndecl)
if (METHOD_SYNCHRONIZED (fndecl) && ! flag_emit_class_files)
{
/* Warp function body with a monitorenter plus monitorexit cleanup. */
/* Wrap function body with a monitorenter plus monitorexit cleanup. */
tree enter, exit, lock;
if (METHOD_STATIC (fndecl))
lock = build_class_ref (DECL_CONTEXT (fndecl));
......
......@@ -1844,6 +1844,165 @@ expand_invoke (opcode, method_ref_index, nargs)
}
}
/* Create a stub which will be put into the vtable but which will call
a JNI function. */
tree
build_jni_stub (method)
tree method;
{
tree jnifunc, call, args, body, lookup_arg, method_sig, arg_types;
tree jni_func_type, tem;
tree env_var, res_var = NULL_TREE, block;
tree method_args, res_type;
tree klass = DECL_CONTEXT (method);
int from_class = ! CLASS_FROM_SOURCE_P (klass);
klass = build_class_ref (klass);
if (! METHOD_NATIVE (method) || ! flag_jni)
abort ();
DECL_ARTIFICIAL (method) = 1;
DECL_EXTERNAL (method) = 0;
env_var = build_decl (VAR_DECL, get_identifier ("env"), ptr_type_node);
if (TREE_TYPE (TREE_TYPE (method)) != void_type_node)
{
res_var = build_decl (VAR_DECL, get_identifier ("res"),
TREE_TYPE (TREE_TYPE (method)));
TREE_CHAIN (env_var) = res_var;
}
/* One strange way that the front ends are different is that they
store arguments differently. */
if (from_class)
method_args = DECL_ARGUMENTS (method);
else
method_args = BLOCK_EXPR_DECLS (DECL_FUNCTION_BODY (method));
block = build_block (env_var, NULL_TREE, NULL_TREE,
method_args, NULL_TREE);
TREE_SIDE_EFFECTS (block) = 1;
/* When compiling from source we don't set the type of the block,
because that will prevent patch_return from ever being run. */
if (from_class)
TREE_TYPE (block) = TREE_TYPE (TREE_TYPE (method));
/* Compute the local `env' by calling _Jv_GetJNIEnvNewFrame. */
body = build (MODIFY_EXPR, ptr_type_node, env_var,
build (CALL_EXPR, ptr_type_node,
build_address_of (soft_getjnienvnewframe_node),
build_tree_list (NULL_TREE, klass),
NULL_TREE));
CAN_COMPLETE_NORMALLY (body) = 1;
/* All the arguments to this method become arguments to the
underlying JNI function. If we had to wrap object arguments in a
special way, we would do that here. */
args = NULL_TREE;
for (tem = method_args; tem != NULL_TREE; tem = TREE_CHAIN (tem))
args = tree_cons (NULL_TREE, tem, args);
args = nreverse (args);
arg_types = TYPE_ARG_TYPES (TREE_TYPE (method));
/* For a static method the second argument is the class. For a
non-static method the second argument is `this'; that is already
available in the argument list. */
if (METHOD_STATIC (method))
{
args = tree_cons (NULL_TREE, klass, args);
arg_types = tree_cons (NULL_TREE, object_ptr_type_node, arg_types);
}
/* The JNIEnv structure is the first argument to the JNI function. */
args = tree_cons (NULL_TREE, env_var, args);
arg_types = tree_cons (NULL_TREE, ptr_type_node, arg_types);
/* We call _Jv_LookupJNIMethod to find the actual underlying
function pointer. _Jv_LookupJNIMethod will throw the appropriate
exception if this function is not found at runtime. */
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))));
tem = DECL_NAME (method);
lookup_arg
= tree_cons (NULL_TREE, klass,
tree_cons (NULL_TREE, build_utf8_ref (tem), lookup_arg));
jni_func_type
= build_pointer_type (build_function_type (TREE_TYPE (TREE_TYPE (method)),
arg_types));
jnifunc = build (CALL_EXPR, ptr_type_node,
build_address_of (soft_lookupjnimethod_node),
lookup_arg, NULL_TREE);
/* Now we make the actual JNI call via the resulting function
pointer. */
call = build (CALL_EXPR, TREE_TYPE (TREE_TYPE (method)),
build1 (NOP_EXPR, jni_func_type, jnifunc),
args, NULL_TREE);
/* If the JNI call returned a result, capture it here. If we had to
unwrap JNI object results, we would do that here. */
if (res_var != NULL_TREE)
call = build (MODIFY_EXPR, TREE_TYPE (TREE_TYPE (method)),
res_var, call);
TREE_SIDE_EFFECTS (call) = 1;
CAN_COMPLETE_NORMALLY (call) = 1;
body = build (COMPOUND_EXPR, void_type_node, body, call);
TREE_SIDE_EFFECTS (body) = 1;
/* Now free the environment we allocated. */
call = build (CALL_EXPR, ptr_type_node,
build_address_of (soft_jnipopsystemframe_node),
build_tree_list (NULL_TREE, env_var),
NULL_TREE);
TREE_SIDE_EFFECTS (call) = 1;
CAN_COMPLETE_NORMALLY (call) = 1;
body = build (COMPOUND_EXPR, void_type_node, body, call);
TREE_SIDE_EFFECTS (body) = 1;
/* Finally, do the return. When compiling from source we rely on
patch_return to patch the return value -- because DECL_RESULT is
not set at the time this function is called. */
if (from_class)
{
res_type = void_type_node;
if (res_var != NULL_TREE)
{
tree drt;
if (! DECL_RESULT (method))
abort ();
/* Make sure we copy the result variable to the actual
result. We use the type of the DECL_RESULT because it
might be different from the return type of the function:
it might be promoted. */
drt = TREE_TYPE (DECL_RESULT (method));
if (drt != TREE_TYPE (res_var))
res_var = build1 (CONVERT_EXPR, drt, res_var);
res_var = build (MODIFY_EXPR, drt, DECL_RESULT (method), res_var);
TREE_SIDE_EFFECTS (res_var) = 1;
}
}
else
{
/* This is necessary to get patch_return to run. */
res_type = NULL_TREE;
}
body = build (COMPOUND_EXPR, void_type_node, body,
build1 (RETURN_EXPR, res_type, res_var));
TREE_SIDE_EFFECTS (body) = 1;
BLOCK_EXPR_BODY (block) = body;
return block;
}
/* Expand an operation to extract from or store into a field.
IS_STATIC is 1 iff the field is static.
......
......@@ -63,7 +63,7 @@ DEFTREECODE (CATCH_EXPR, "catch", '1', 1)
DEFTREECODE (SYNCHRONIZED_EXPR, "synchronized", 'e', 2)
/* Throw statement.
Operand 0 is the throw expresion. */
Operand 0 is the throw expression. */
DEFTREECODE (THROW_EXPR, "throw", '1', 1)
/* Conditional operator.
......@@ -93,3 +93,8 @@ DEFTREECODE (CLASS_LITERAL, "class_literal", '1', 1)
is used for context detection, so that special rules can be
enforced. */
DEFTREECODE (INSTANCE_INITIALIZERS_EXPR, "instance_initializers_expr", '1', 1)
/*
Local variables:
mode:c
End:
*/
......@@ -135,6 +135,11 @@ extern int flag_assume_compiled;
extern int flag_emit_class_files;
/* When non zero, assume all native functions are implemented with
JNI, not CNI. */
extern int flag_jni;
/* When non zero, we emit xref strings. Values of the flag for xref
backends are defined in xref.h. */
......@@ -296,6 +301,9 @@ extern tree soft_checkarraystore_node;
extern tree soft_monitorenter_node;
extern tree soft_monitorexit_node;
extern tree soft_lookupinterfacemethod_node;
extern tree soft_lookupjnimethod_node;
extern tree soft_getjnienvnewframe_node;
extern tree soft_jnipopsystemframe_node;
extern tree soft_fmod_node;
extern tree soft_exceptioninfo_call_node;
extern tree soft_idiv_node;
......@@ -514,6 +522,9 @@ struct lang_decl
tree inner_access; /* The identifier of the access method
used for invocation from inner classes */
int nap; /* Number of artificial parameters */
int native : 1; /* Nonzero if this is a native
method. */
};
/* init_test_table hash table entry structure. */
......@@ -649,6 +660,7 @@ extern tree build_known_method_ref PARAMS ((tree, tree, tree, tree, tree));
extern tree build_class_init PARAMS ((tree, tree));
extern tree build_invokevirtual PARAMS ((tree, tree));
extern tree build_invokeinterface PARAMS ((tree, tree));
extern tree build_jni_stub PARAMS ((tree));
extern tree invoke_build_dtable PARAMS ((int, tree));
extern tree build_field_ref PARAMS ((tree, tree, tree));
extern void pushdecl_force_head PARAMS ((tree));
......@@ -773,7 +785,7 @@ struct rtx_def * java_lang_expand_expr PARAMS ((tree, rtx, enum machine_mode,
#define METHOD_STATIC(DECL) DECL_LANG_FLAG_2 (DECL)
#define METHOD_FINAL(DECL) DECL_LANG_FLAG_3 (DECL)
#define METHOD_SYNCHRONIZED(DECL) DECL_LANG_FLAG_4 (DECL)
#define METHOD_NATIVE(DECL) DECL_EXTERNAL(DECL)
#define METHOD_NATIVE(DECL) (DECL_LANG_SPECIFIC(DECL)->native)
#define METHOD_ABSTRACT(DECL) DECL_LANG_FLAG_5 (DECL)
#define METHOD_TRANSIENT(DECL) DECL_LANG_FLAG_6 (DECL)
......
......@@ -684,9 +684,22 @@ parse_class_file ()
{
JCF *jcf = current_jcf;
if (METHOD_NATIVE (method) || METHOD_ABSTRACT (method))
if (METHOD_ABSTRACT (method))
continue;
if (METHOD_NATIVE (method))
{
if (! flag_jni)
continue;
DECL_MAX_LOCALS (method)
= list_length (TYPE_ARG_TYPES (TREE_TYPE (method)));
start_java_method (method);
give_name_to_locals (jcf);
expand_expr_stmt (build_jni_stub (method));
end_java_method ();
continue;
}
if (DECL_CODE_OFFSET (method) == 0)
{
error ("missing Code attribute");
......
......@@ -35,6 +35,7 @@ DEFINE_LANG_NAME ("Java")
{ "-femit-class-files", "Dump class files to <name>.class" },
{ "-fuse-boehm-gc", "Generate code for Boehm GC" },
{ "-fhash-synchronization", "Don't put synchronization structure in each object" },
{ "-fjni", "Assume native functions are implemented using JNI" },
#if ! USE_CPPLIB
{ "-MD", "Print dependencies to FILE.d" },
{ "-MMD", "Print dependencies to FILE.d" },
......
/* Definitions for specs for the GNU compiler for the Java(TM) language.
Copyright (C) 1996, 1998, 1999 Free Software Foundation, Inc.
Copyright (C) 1996, 1998, 1999, 2000 Free Software Foundation, Inc.
This file is part of GNU CC.
......@@ -36,6 +36,7 @@ The Free Software Foundation is independent of Sun Microsystems, Inc. */
%{f*} %{+e*} %{aux-info*} %{Qn:-fno-ident}\
%{I*}\
%{MD} %{MMD} %{M} %{MM}\
%{fjni:%{femit-class-file:%e-fjni and -femit-class-file are incompatible}}\
%{pg:%{fomit-frame-pointer:%e-pg and -fomit-frame-pointer are incompatible}}\
%{S:%W{o*}%{!o*:-o %b.s}}%{!S:-o %{|!pipe:%g.s}} |\n\
%{!S:as %a %Y\
......
......@@ -117,6 +117,10 @@ int flag_use_boehm_gc = 0;
object to its synchronization structure. */
int flag_hash_synchronization;
/* When non zero, assume all native functions are implemented with
JNI, not CNI. */
int flag_jni = 0;
/* From gcc/flags.h, and indicates if exceptions are turned on or not. */
extern int flag_new_exceptions;
......@@ -135,7 +139,8 @@ lang_f_options[] =
{"emit-class-files", &flag_emit_class_files, 1},
{"use-divide-subroutine", &flag_use_divide_subroutine, 1},
{"use-boehm-gc", &flag_use_boehm_gc, 1},
{"hash-synchronization", &flag_hash_synchronization, 1}
{"hash-synchronization", &flag_hash_synchronization, 1},
{"jni", &flag_jni, 1}
};
JCF *current_jcf;
......
......@@ -7297,10 +7297,19 @@ java_complete_expand_methods (class_decl)
/* First, do the ordinary methods. */
for (decl = first_decl; decl; decl = TREE_CHAIN (decl))
{
/* Skip abstract or native methods */
if (METHOD_ABSTRACT (decl) || METHOD_NATIVE (decl)
/* Skip abstract or native methods -- but do handle native
methods when generating JNI stubs. */
if (METHOD_ABSTRACT (decl)
|| (! flag_jni && METHOD_NATIVE (decl))
|| DECL_CONSTRUCTOR_P (decl) || DECL_CLINIT_P (decl))
continue;
if (METHOD_NATIVE (decl))
{
tree body = build_jni_stub (decl);
BLOCK_EXPR_BODY (DECL_FUNCTION_BODY (decl)) = body;
}
java_complete_expand_method (decl);
}
......@@ -7430,7 +7439,7 @@ java_complete_expand_method (mdecl)
{
block_body = java_complete_tree (block_body);
if (!flag_emit_xref)
if (! flag_emit_xref && ! METHOD_NATIVE (mdecl))
check_for_initialization (block_body);
ctxp->explicit_constructor_p = 0;
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment