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]

Patch: g++ -vs- Java exceptions, take 2


Here's the second version of my Java-exceptions-for-g++ patch.
This one makes the generated code work when sjlj exceptions are in use.
It also gives an error if an invalid Java catch or throw is attempted
(for instance, catching by reference is not supported).

I didn't try the fuller fix of making the Java compiler emit typeinfo
objects for Java classes.  We can still implement this at a later
date; meanwhile, this patch is a definite improvement over the current
state of affairs.

Ok to commit?

2000-02-28  Tom Tromey  <tromey@cygnus.com>

	* cp-tree.h (build_java_class_ref): Declare.
	* init.c (build_java_class_ref): No longer static.
	* except.c (expand_throw): Generate a Java-style `throw' if the
	thrown object is a "Java" object.
	(initialize_handler_parm): Generate a Java-style lookup of
	exception info if the caught object is a "Java" object.
	(catch_language, catch_language_init): New globals.
	(decl_is_java_type): New function.
	(expand_start_catch_block): Don't call push_eh_info() or
	push_eh_cleanup() when handling a Java-style "catch".  Pass Java
	class reference to build_catch_block.

Tom

Index: gcc/cp/cp-tree.h
===================================================================
RCS file: /cvs/gcc/egcs/gcc/cp/cp-tree.h,v
retrieving revision 1.405
diff -u -r1.405 cp-tree.h
--- cp-tree.h	2000/02/21 04:19:11	1.405
+++ cp-tree.h	2000/02/29 03:47:25
@@ -3913,6 +3913,7 @@
 extern void begin_init_stmts                    PARAMS ((tree *, tree *));
 extern tree finish_init_stmts                   PARAMS ((tree, tree));
 extern void initialize_vtbl_ptrs                PARAMS ((tree, tree));
+extern tree build_java_class_ref                PARAMS ((tree));
 
 /* in input.c */
 
Index: gcc/cp/except.c
===================================================================
RCS file: /cvs/gcc/egcs/gcc/cp/except.c,v
retrieving revision 1.95
diff -u -r1.95 except.c
--- except.c	2000/01/26 20:51:34	1.95
+++ except.c	2000/02/29 03:47:28
@@ -55,6 +55,7 @@
 static int complete_ptr_ref_or_void_ptr_p PARAMS ((tree, tree));
 static void initialize_handler_parm PARAMS ((tree));
 static tree expand_throw PARAMS ((tree));
+static int decl_is_java_type PARAMS ((tree decl, int err));
 
 #if 0
 /* This is the startup, and finish stuff per exception table.  */
@@ -92,6 +93,14 @@
 #include "insn-flags.h"
 #include "obstack.h"
 
+/* In a given translation unit we are constrained to catch only C++
+   types or only Java types.  `catch_language' holds the current type,
+   and `catch_language_init' registers whether `catch_language' has
+   been set.  */
+
+static int catch_language_init = 0;
+static int catch_language;
+
 /* ======================================================================
    Briefly the algorithm works like this:
 
@@ -450,6 +459,49 @@
   return build_function_call (terminate_node, NULL_TREE);
 }
 
+/* Return nonzero value if DECL is a Java type suitable for catch or
+   throw.  */
+
+static int
+decl_is_java_type (decl, err)
+     tree decl;
+     int err;
+{
+  int r = (TREE_CODE (decl) == POINTER_TYPE
+	   && TREE_CODE (TREE_TYPE (decl)) == RECORD_TYPE
+	   && TYPE_FOR_JAVA (TREE_TYPE (decl)));
+
+  if (err)
+    {
+      if (TREE_CODE (decl) == REFERENCE_TYPE
+	  && TREE_CODE (TREE_TYPE (decl)) == RECORD_TYPE
+	  && TYPE_FOR_JAVA (TREE_TYPE (decl)))
+	{
+	  /* Can't throw a reference.  */
+	  cp_error ("type `%T' is disallowed in Java `throw' or `catch'",
+		    decl);
+	}
+
+      if (r)
+	{
+	  tree jthrow_node
+	    = IDENTIFIER_GLOBAL_VALUE (get_identifier ("jthrowable"));
+	  if (jthrow_node == NULL_TREE)
+	    fatal ("call to Java `catch' or `throw', while `jthrowable' undefined");
+	  jthrow_node = TREE_TYPE (TREE_TYPE (jthrow_node));
+
+	  if (! DERIVED_FROM_P (jthrow_node, TREE_TYPE (decl)))
+	    {
+	      /* Thrown object must be a Throwable.  */
+	      cp_error ("type `%T' is not derived from `java::lang::Throwable'",
+			TREE_TYPE (decl));
+	    }
+	}
+    }
+
+  return r;
+}
+
 /* Initialize the catch parameter DECL.  */
 
 static void 
@@ -459,6 +511,7 @@
   tree exp;
   tree init;
   tree init_type;
+  int lang;
 
   /* Make sure we mark the catch param as used, otherwise we'll get a
      warning about an unused ((anonymous)).  */
@@ -470,8 +523,43 @@
       && TREE_CODE (init_type) != POINTER_TYPE)
     init_type = build_reference_type (init_type);
 
-  exp = get_eh_value ();
+  if (decl_is_java_type (init_type, 0))
+    {
+      tree fn
+	= builtin_function ("_Jv_exception_info", 
+			    build_function_type (ptr_type_node,
+						 tree_cons (NULL_TREE,
+							    void_type_node,
+							    NULL_TREE)),
+			    0, NOT_BUILT_IN, NULL_PTR);
+
+      exp = build (CALL_EXPR, ptr_type_node,
+		   build1 (ADDR_EXPR, build_pointer_type (TREE_TYPE (fn)),
+			   fn),
+		   NULL_TREE, NULL_TREE);
+      TREE_SIDE_EFFECTS (exp) = 1;
+      lang = EH_LANG_Java;
 
+      set_exception_lang_code (EH_LANG_Java);
+      set_exception_version_code (1);
+    }
+  else
+    {
+      exp = get_eh_value ();
+      lang = EH_LANG_C_plus_plus;
+    }
+
+  if (catch_language_init)
+    {
+      if (lang != catch_language)
+	error ("mixing C++ and Java `catch'es in single translation unit");
+    }
+  else
+    {
+      catch_language_init = 1;
+      catch_language = lang;
+    }
+
   /* Since pointers are passed by value, initialize a reference to
      pointer catch parm with the address of the value slot.  */ 
   if (TREE_CODE (init_type) == REFERENCE_TYPE 
@@ -524,15 +612,28 @@
      cleanup.  */
   compound_stmt_1 = begin_compound_stmt (/*has_no_scope=*/0);
 
-  if (decl)
-    type = build_eh_type_type_ref (TREE_TYPE (decl));
-  else
-    type = NULL_TREE;
-  begin_catch_block (type);
+  if (! decl || ! decl_is_java_type (TREE_TYPE (decl), 1))
+    {
+      /* The ordinary C++ case.  */
 
-  push_eh_info ();
-  push_eh_cleanup ();
+      if (decl)
+	type = build_eh_type_type_ref (TREE_TYPE (decl));
+      else
+	type = NULL_TREE;
+      begin_catch_block (type);
 
+      push_eh_info ();
+      push_eh_cleanup ();
+    }
+  else
+    {
+      /* The Java case.  In this case, the match_info is a pointer to
+	 the Java class object.  We assume that the class is a
+	 compiled class.  */
+      tree ref = build_java_class_ref (TREE_TYPE (TREE_TYPE (decl)));
+      begin_catch_block (build1 (ADDR_EXPR, jclass_node, ref));
+    }
+
   /* Create a binding level for the parm.  */
   compound_stmt_2 = begin_compound_stmt (/*has_no_scope=*/0);
 
@@ -734,7 +835,35 @@
   if (! doing_eh (1))
     return error_mark_node;
 
-  if (exp)
+  if (exp
+      && decl_is_java_type (TREE_TYPE (exp), 1))
+    {
+      /* A Java `throw' statement.  */
+      tree args = tree_cons (NULL_TREE, exp, NULL);
+
+      fn = get_identifier (exceptions_via_longjmp
+			   ? "_Jv_Sjlj_throw"
+			   : "_Jv_Throw");
+      if (IDENTIFIER_GLOBAL_VALUE (fn))
+	fn = IDENTIFIER_GLOBAL_VALUE (fn);
+      else
+	{
+	  /* Declare _Jv_Throw (void *), as defined in Java's
+	     exception.cc.  */
+	  tree tmp;
+	  tmp = tree_cons (NULL_TREE, ptr_type_node, void_list_node);
+	  fn = build_lang_decl (FUNCTION_DECL, fn,
+				build_function_type (ptr_type_node, tmp));
+	  DECL_EXTERNAL (fn) = 1;
+	  TREE_PUBLIC (fn) = 1;
+	  DECL_ARTIFICIAL (fn) = 1;
+	  pushdecl_top_level (fn);
+	  make_function_rtl (fn);
+	}
+
+      exp = build_function_call (fn, args);
+    }
+  else if (exp)
     {
       tree throw_type;
       tree cleanup = NULL_TREE, e;
Index: gcc/cp/init.c
===================================================================
RCS file: /cvs/gcc/egcs/gcc/cp/init.c,v
retrieving revision 1.165
diff -u -r1.165 init.c
--- init.c	2000/02/21 04:19:12	1.165
+++ init.c	2000/02/29 03:47:36
@@ -45,7 +45,6 @@
 static void expand_virtual_init PARAMS ((tree, tree));
 static tree sort_member_init PARAMS ((tree));
 static tree initializing_context PARAMS ((tree));
-static tree build_java_class_ref PARAMS ((tree));
 static void expand_cleanup_for_base PARAMS ((tree, tree));
 static tree get_temp_regvar PARAMS ((tree, tree));
 static tree dfs_initialize_vtbl_ptrs PARAMS ((tree, void *));
@@ -2076,7 +2075,7 @@
 
 /* Given a Java class, return a decl for the corresponding java.lang.Class. */
 
-static tree
+tree
 build_java_class_ref (type)
      tree type;
 {

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