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


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

C++ patch: Add support for calling Java interfaces


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)

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