This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
C++ patch: Add support for calling Java interfaces
- To: gcc-patches at gcc dot gnu dot org, java-patches at gcc dot gnu dot org
- Subject: C++ patch: Add support for calling Java interfaces
- From: Bryce McKinlay <bryce at albatross dot co dot nz>
- Date: Wed, 21 Mar 2001 16:22:22 +1200
The following patch adds partial support for Java interfaces to the
C++ compiler. This means that cases like the following are now
possible with CNI:
// Java
interface Iface
{
void a();
}
public class Impl implements Iface
{
native void callA(Iface i);
public void a()
{
System.out.println ("a ok");
}
public static void main(String[] args)
{
Impl i = new Impl();
i.callA(i);
}
}
// C++
#include <Iface.h>
#include <Impl.h>
void
Impl::callA (Iface i)
{
i->a();
}
Until now, code like this would compile but tended to crash the java
runtime, because C++ would attempt a normal vtbl method lookup which
Java does not use for interface dispatch.
C++ doesn't yet understand inheritence among Java interfaces, and gcjh
does not attempt to express this in the generated header file -
currently a cast will be needed in order to call a method declared in
a superinterface. To support this properly might, I suspect, require
more extensive changes to C++ to ensure it remove interface types from
consideration when calculating vtable offsets for non-interface calls.
Calls to java.lang.Object methods are handled correctly.
I would also like to commit this to branch, because it fixes at least
one crash bug in the java runtime (in the File.list(FilenameFilter)
method) and will allow me to finish a complete Java 2 implementation
of the File class without ugly kludges. It doesn't touch much code and
ought to not break anything.
C++ testsuite looks ok. Bootstrapped i686-linux. OK to commit?
regards
[ bryce ]
2001-03-21 Bryce McKinlay <bryce@albatross.co.nz>
* gjavah.c (process_file): Mark interface definitions with
"__attribute__ ((java_interface))".
2001-03-21 Bryce McKinlay <bryce@albatross.co.nz>
Add support for Java interface method calls.
* cp-tree.h (struct lang_type): Add java_interface flag.
(TYPE_JAVA_INTERFACE): New macro.
* tree.c (cp_valid_lang_attribute): Handle "java_interface" attribute
by setting TYPE_JAVA_INTERFACE.
* call.c (build_over_call): If calling a method declared in a
TYPE_JAVA_INTERFACE, call build_java_interface_fn_ref to generate the
expression which resolves the function address.
(build_java_interface_fn_ref): New function.
Index: java/gjavah.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/java/gjavah.c,v
retrieving revision 1.68
diff -u -r1.68 gjavah.c
--- gjavah.c 2001/01/12 17:28:23 1.68
+++ gjavah.c 2001/03/21 03:21:00
@@ -1857,7 +1857,12 @@
generate_access (out, ACC_PUBLIC);
fprintf (out, "\n static ::java::lang::Class class$;\n");
- fputs ("};\n", out);
+ fputs ("}", out);
+
+ if (jcf->access_flags & ACC_INTERFACE)
+ fputs (" __attribute__ ((java_interface))", out);
+
+ fputs (";\n", out);
if (append_count > 0)
fputc ('\n', out);
Index: cp/call.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cp/call.c,v
retrieving revision 1.255.2.7
diff -u -r1.255.2.7 call.c
--- call.c 2001/03/06 15:37:37 1.255.2.7
+++ call.c 2001/03/21 03:21:02
@@ -45,6 +45,7 @@
static int joust PARAMS ((struct z_candidate *, struct z_candidate *, int));
static int compare_ics PARAMS ((tree, tree));
static tree build_over_call PARAMS ((struct z_candidate *, tree, int));
+static tree build_java_interface_fn_ref PARAMS ((tree, tree));
#define convert_like(CONV, EXPR) convert_like_real (CONV, EXPR, NULL_TREE, 0, 0)
#define convert_like_with_context(CONV, EXPR, FN, ARGNO) convert_like_real (CONV, EXPR, FN, ARGNO, 0)
static tree convert_like_real PARAMS ((tree, tree, tree, int, int));
@@ -4262,7 +4263,10 @@
if (TREE_SIDE_EFFECTS (*p))
*p = save_expr (*p);
t = build_pointer_type (TREE_TYPE (fn));
- fn = build_vfn_ref (p, build_indirect_ref (*p, 0), DECL_VINDEX (fn));
+ if (DECL_CONTEXT (fn) && TYPE_JAVA_INTERFACE (DECL_CONTEXT (fn)))
+ fn = build_java_interface_fn_ref (fn, *p);
+ else
+ fn = build_vfn_ref (p, build_indirect_ref (*p, 0), DECL_VINDEX (fn));
TREE_TYPE (fn) = t;
}
else if (DECL_INLINE (fn))
@@ -4295,6 +4299,62 @@
if (IS_AGGR_TYPE (TREE_TYPE (fn)))
fn = build_cplus_new (TREE_TYPE (fn), fn);
return convert_from_reference (fn);
+}
+
+/* Make an expression which yields the address of the Java interface
+ method FN. This is achieved by generating a call to libjava's
+ _Jv_LookupInterfaceMethodIdx(). */
+
+static tree
+build_java_interface_fn_ref (fn, instance)
+ tree fn, instance;
+{
+ tree lookup_args, method, idx;
+ tree endlink = build_void_list_node ();
+ tree t = tree_cons (NULL_TREE, ptr_type_node,
+ tree_cons (NULL_TREE, ptr_type_node,
+ tree_cons (NULL_TREE, java_int_type_node,
+ endlink)));
+ tree lookup_fn = builtin_function ("_Jv_LookupInterfaceMethodIdx",
+ build_function_type (ptr_type_node, t),
+ 0, NOT_BUILT_IN, NULL_PTR);
+ int i;
+
+ /* Look up the pointer to the runtime java.lang.Class object for `instance'.
+ This is the first entry in the vtable. */
+ tree klass_ref = build_vtbl_ref (build_indirect_ref (instance, 0),
+ integer_zero_node);
+
+ /* Get the java.lang.Class pointer for the interface being called. */
+ tree iface = DECL_CONTEXT (fn);
+ tree iface_ref = lookup_field (iface, get_identifier ("class$"), 0, 0);
+ if (!iface_ref || TREE_CODE (iface_ref) != VAR_DECL
+ || DECL_CONTEXT (iface_ref) != iface)
+ {
+ cp_error ("Could not find class$ field in java interface type `%T'",
+ iface);
+ return error_mark_node;
+ }
+ iface_ref = build1 (ADDR_EXPR, build_pointer_type (iface), iface_ref);
+
+ /* Determine the itable index of FN. */
+ i = 1;
+ for (method = TYPE_METHODS (iface); method; method = TREE_CHAIN (method))
+ {
+ if (DECL_ARTIFICIAL (method) || !DECL_VIRTUAL_P (method))
+ continue;
+ if (fn == method)
+ break;
+ i++;
+ }
+ idx = build_int_2 (i, 0);
+
+ lookup_args = tree_cons (NULL_TREE, klass_ref,
+ tree_cons (NULL_TREE, iface_ref,
+ build_tree_list (NULL_TREE, idx)));
+ lookup_fn = build1 (ADDR_EXPR, build_pointer_type (TREE_TYPE (lookup_fn)),
+ lookup_fn);
+ return build (CALL_EXPR, ptr_type_node, lookup_fn, lookup_args, NULL_TREE);
}
/* Returns the value to use for the in-charge parameter when making a
Index: cp/tree.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cp/tree.c,v
retrieving revision 1.232.2.4
diff -u -r1.232.2.4 tree.c
--- tree.c 2001/03/20 22:03:47 1.232.2.4
+++ tree.c 2001/03/21 03:21:06
@@ -2212,6 +2212,19 @@
tree decl ATTRIBUTE_UNUSED;
tree type ATTRIBUTE_UNUSED;
{
+ if (is_attribute_p ("java_interface", attr_name))
+ {
+ if (attr_args != NULL_TREE
+ || decl != NULL_TREE
+ || ! CLASS_TYPE_P (type)
+ || ! TYPE_FOR_JAVA (type))
+ {
+ error ("`java_interface' attribute can only be applied to Java class definitions");
+ return 0;
+ }
+ TYPE_JAVA_INTERFACE (type) = 1;
+ return 1;
+ }
if (is_attribute_p ("com_interface", attr_name))
{
if (! flag_vtable_thunks)