Java/12725: Binary Compatibility

Andrew Haley aph@redhat.com
Wed Oct 22 17:44:00 GMT 2003


This patch handles calls to interpreted code from native code, even
the very tricky problem of a class in a catch handler being provided
by interpreted code.

You really can do something like

public class one
{
 public static void main (String[] s)
  {
    try
      {
        foo.main (s);
      }
    catch (Kludge _)
      {
        System.out.println (_);
      }
  }
}
public class foo
{
  public static void main (String argv[]) throws Kludge
  {
    throw new Kludge();
  }
}
public class Kludge extends Exception
{
  public String toString() { return "zounds!"; }
}

 $ gcj one.java foo.java -findirect-dispatch --main=one
 $ gcj -fpic foo.java -o lib-foo.so -shared -findirect-dispatch
 $ gcj -C Kludge.java
 $ ./a.out 
zounds!

And this runs an executable which dynamically loads lib-foo.so and
invokes the interpreter to load Kludge.class.

Also, you have the additional benefit that you can compile and run
JARs with external dependencies which are resolved at runtime.


It's still a prototype, because there are some remaining issues:

* Resolving static methods and classes is not thread safe.

* There are many linear (rather than hash table) searches, both at
  compile time and run time.

* There is functional overlap between the constant pool and the
  address and offset tables.  Perhaps they should be unified.

* The way handlers for catch regions are handled is rather inelegant.

* CNI code is not binary compatible.

... and probably more.


Still, as Binary Compatibility is to be an important feature of gcj
3.5 I want the prototype to be available to users of gcj 3.4.  It
won't be enabled without -findirect-dispatch.

Andrew.


2003-10-22  Andrew Haley  <aph@redhat.com>

	* lang.c (LANG_HOOKS_GET_CALLEE_FNDECL): New.
	(java_get_callee_fndecl): New.

	* jcf-parse.c (java_parse_file): Call emit_catch_table().

	* java-tree.h (ctable_decl): New.
	(catch_classes):  New.
	(java_tree_index): Add JTI_CTABLE_DECL, JTI_CATCH_CLASSES.

	* decl.c (java_init_decl_processing): Add catch_class_type.
	Add ctable_decl.
	Add catch_classes field.

	* class.c (build_indirect_class_ref): Break out from
	build_class_ref.
	(make_field_value): Check flag_indirect_dispatch.
	(make_class_data): Ditto.
	Tidy uses of PUSH_FIELD_VALUE.
	Add field catch_classes.
	(make_catch_class_record): New.

	* java-tree.h (PUSH_FIELD_VALUE): Tidy.

2003-10-22  Andrew Haley  <aph@redhat.com>

	* java/lang/natClass.cc (initializeClass): Call
	_Jv_linkExceptionClassTable.
	(_Jv_LinkSymbolTable): Call )_Jv_ThrowNoSuchMethodError.  Call
	_Jv_Defer_Resolution on a method whose ncode is NULL.
	(_Jv_linkExceptionClassTable): New function.
	(_Jv_LayoutVTableMethods): If superclass looks like a constant pool
	entry, look it up.
	* java/lang/Class.h (struct _Jv_CatchClass): New.
	(_Jv_linkExceptionClassTable): New friend.
	(_Jv_Defer_Resolution): New friend.
	(class Class.catch_classes): New field.
	* include/java-interp.h (Jv_Defer_Resolution): New method.
	(_Jv_PrepareClass): Make a friend of _Jv_MethodBase.
	(_Jv_MethodBase.deferred): New field.
	(_Jv_Defer_Resolution): New function.
	* resolve.cc (_Jv_PrepareClass): Resolve deferred handlers.
	* exception.cc (get_ttype_entry): Change return type to void**.
	(PERSONALITY_FUNCTION): Remove all code related to using a
	Utf8Const* for a match type.  Change match type to be a pointer to
	a pointer, rather than a pointer to a Class.
	* defineclass.cc (handleCodeAttribute): Initialize
	method->deferred.
	(handleMethodsEnd): Likewise.

Index: gcc/java/class.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/java/class.c,v
retrieving revision 1.171
diff -c -2 -p -r1.171 class.c
*** gcc/java/class.c	9 Oct 2003 16:21:56 -0000	1.171
--- gcc/java/class.c	22 Oct 2003 17:19:46 -0000
*************** build_utf8_ref (tree name)
*** 809,812 ****
--- 809,826 ----
  }
  
+ /* Like build_class_ref, but instead of a direct reference generate a
+    pointer into the constant pool.  */
+ 
+ static tree
+ build_indirect_class_ref (tree type)
+ {
+   int index;
+   tree cl;
+   index = alloc_class_constant (type);
+   cl = build_ref_from_constant_pool (index); 
+   TREE_TYPE (cl) = promote_type (class_ptr_type);
+   return cl;
+ }
+ 
  /* Build a reference to the class TYPE.
     Also handles primitive types and array types. */
*************** build_class_ref (tree type)
*** 821,824 ****
--- 835,844 ----
        if (TREE_CODE (type) == POINTER_TYPE)
  	type = TREE_TYPE (type);
+ 
+       if  (flag_indirect_dispatch 
+ 	   && type != current_class
+ 	   && TREE_CODE (type) == RECORD_TYPE)
+ 	return build_indirect_class_ref (type);
+ 
        if (TREE_CODE (type) == RECORD_TYPE)
  	{
*************** build_class_ref (tree type)
*** 903,914 ****
      }
    else
!     {
!       int index;
!       tree cl;
!       index = alloc_class_constant (type);
!       cl = build_ref_from_constant_pool (index); 
!       TREE_TYPE (cl) = promote_type (class_ptr_type);
!       return cl;
!     }
  }
  
--- 923,927 ----
      }
    else
!     return build_indirect_class_ref (type);
  }
  
*************** make_field_value (tree fdecl)
*** 1062,1066 ****
    int flags;
    tree type = TREE_TYPE (fdecl);
!   int resolved = is_compiled_class (type);
  
    START_RECORD_CONSTRUCTOR (finit, field_type_node);
--- 1075,1079 ----
    int flags;
    tree type = TREE_TYPE (fdecl);
!   int resolved = is_compiled_class (type) && ! flag_indirect_dispatch;
  
    START_RECORD_CONSTRUCTOR (finit, field_type_node);
*************** make_class_data (tree type)
*** 1423,1427 ****
    if (super == NULL_TREE)
      super = null_pointer_node;
!   else if (assume_compiled (IDENTIFIER_POINTER (DECL_NAME (type_decl)))
  	   && assume_compiled (IDENTIFIER_POINTER (DECL_NAME (TYPE_NAME (super)))))
      super = build_class_ref (super);
--- 1436,1441 ----
    if (super == NULL_TREE)
      super = null_pointer_node;
!   else if (! flag_indirect_dispatch
! 	   && assume_compiled (IDENTIFIER_POINTER (DECL_NAME (type_decl)))
  	   && assume_compiled (IDENTIFIER_POINTER (DECL_NAME (TYPE_NAME (super)))))
      super = build_class_ref (super);
*************** make_class_data (tree type)
*** 1493,1497 ****
  
    if (flag_indirect_dispatch)
!     PUSH_FIELD_VALUE (cons, "vtable_method_count", integer_minus_one_node)
    else
      PUSH_FIELD_VALUE (cons, "vtable_method_count", TYPE_NVIRTUALS (type));
--- 1507,1511 ----
  
    if (flag_indirect_dispatch)
!     PUSH_FIELD_VALUE (cons, "vtable_method_count", integer_minus_one_node);
    else
      PUSH_FIELD_VALUE (cons, "vtable_method_count", TYPE_NVIRTUALS (type));
*************** make_class_data (tree type)
*** 1506,1510 ****
  
    if (flag_indirect_dispatch)
!     PUSH_FIELD_VALUE (cons, "vtable", null_pointer_node)
    else
      PUSH_FIELD_VALUE (cons, "vtable",
--- 1520,1524 ----
  
    if (flag_indirect_dispatch)
!     PUSH_FIELD_VALUE (cons, "vtable", null_pointer_node);
    else
      PUSH_FIELD_VALUE (cons, "vtable",
*************** make_class_data (tree type)
*** 1541,1545 ****
        TREE_CONSTANT (atable_decl) = 1;
      }
! 
    PUSH_FIELD_VALUE (cons, "interfaces", interfaces);
    PUSH_FIELD_VALUE (cons, "loader", null_pointer_node);
--- 1555,1561 ----
        TREE_CONSTANT (atable_decl) = 1;
      }
!  
!   PUSH_FIELD_VALUE (cons, "catch_classes",
! 		    build1 (ADDR_EXPR, ptr_type_node, ctable_decl)); 
    PUSH_FIELD_VALUE (cons, "interfaces", interfaces);
    PUSH_FIELD_VALUE (cons, "loader", null_pointer_node);
*************** emit_symbol_table (tree name, tree the_t
*** 2210,2213 ****
--- 2226,2270 ----
    return the_table;
  }
+ 
+ /* make an entry for the catch_classes list.  */
+ tree
+ make_catch_class_record (tree catch_class, tree classname)
+ {
+   tree entry;
+   tree type = TREE_TYPE (TREE_TYPE (ctable_decl));
+   START_RECORD_CONSTRUCTOR (entry, type);
+   PUSH_FIELD_VALUE (entry, "address", catch_class);
+   PUSH_FIELD_VALUE (entry, "classname", classname);
+   FINISH_RECORD_CONSTRUCTOR (entry);
+   return entry;
+ }
+ 
+ 
+ /* Generate the list of Throwable classes that are caught by exception
+    handlers in this compilation.  */
+ void 
+ emit_catch_table (void)
+ {
+   tree table, table_size, array_type;
+   catch_classes 
+     = tree_cons (NULL, 
+ 		 make_catch_class_record (null_pointer_node, null_pointer_node),
+ 		 catch_classes);
+   catch_classes = nreverse (catch_classes);
+   catch_classes 
+     = tree_cons (NULL, 
+ 		 make_catch_class_record (null_pointer_node, null_pointer_node),
+ 		 catch_classes);
+   table_size = build_index_type (build_int_2 (list_length (catch_classes), 0));
+   array_type 
+     = build_array_type (TREE_TYPE (TREE_TYPE (ctable_decl)), table_size);
+   table = build_decl (VAR_DECL, DECL_NAME (ctable_decl), array_type);
+   DECL_INITIAL (table) = build_constructor (array_type, catch_classes);
+   TREE_STATIC (table) = 1;
+   TREE_READONLY (table) = 1;  
+   rest_of_decl_compilation (table, NULL, 1, 0);
+   ctable_decl = table;
+ }
+  
  
  void
Index: gcc/java/decl.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/java/decl.c,v
retrieving revision 1.168
diff -c -2 -p -r1.168 decl.c
*** gcc/java/decl.c	9 Oct 2003 16:21:56 -0000	1.168
--- gcc/java/decl.c	22 Oct 2003 17:19:46 -0000
*************** java_init_decl_processing (void)
*** 664,667 ****
--- 664,684 ----
      }
    
+   {  
+     tree catch_class_type = make_node (RECORD_TYPE);
+     PUSH_FIELD (catch_class_type, field, "address", utf8const_ptr_type);
+     PUSH_FIELD (catch_class_type, field, "classname", ptr_type_node);
+     FINISH_RECORD (catch_class_type);
+     
+     ctable_decl 
+       = build_decl (VAR_DECL, get_identifier ("catch_classes"), 
+ 		    build_array_type 
+ 		    (catch_class_type, 0));
+     DECL_EXTERNAL (ctable_decl) = 1;
+     TREE_STATIC (ctable_decl) = 1;
+     TREE_READONLY (ctable_decl) = 1;
+     TREE_CONSTANT (ctable_decl) = 1;
+     pushdecl (ctable_decl);  
+   }
+ 
    PUSH_FIELD (object_type_node, field, "vtable", dtable_ptr_type);
    /* This isn't exactly true, but it is what we have in the source.
*************** java_init_decl_processing (void)
*** 703,706 ****
--- 720,724 ----
    PUSH_FIELD (class_type_node, field, "atable_syms", 
    	      symbols_array_ptr_type);
+   PUSH_FIELD (class_type_node, field, "catch_classes", ptr_type_node);
    PUSH_FIELD (class_type_node, field, "interfaces",
  	      build_pointer_type (class_ptr_type));
Index: gcc/java/except.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/java/except.c,v
retrieving revision 1.39
diff -c -2 -p -r1.39 except.c
*** gcc/java/except.c	20 Aug 2003 17:27:54 -0000	1.39
--- gcc/java/except.c	22 Oct 2003 17:19:46 -0000
*************** prepare_eh_table_type (tree type)
*** 314,346 ****
    tree exp;
  
!   /* The "type" (metch_info) in a (Java) exception table is one:
     * a) NULL - meaning match any type in a try-finally.
!    * b) a pointer to a (compiled) class (low-order bit 0).
!    * c) a pointer to the Utf8Const name of the class, plus one
!    * (which yields a value with low-order bit 1). */
  
    if (type == NULL_TREE)
      exp = NULL_TREE;
!   else if (is_compiled_class (type))
!     exp = build_class_ref (type);
    else
      {
!       tree ctype = make_node (RECORD_TYPE);
!       tree field = NULL_TREE;
!       tree cinit, decl;
        tree utf8_ref = build_utf8_ref (DECL_NAME (TYPE_NAME (type)));
        char buf[64];
        sprintf (buf, "%s_ref", 
  	       IDENTIFIER_POINTER (DECL_NAME (TREE_OPERAND (utf8_ref, 0))));
!       PUSH_FIELD (ctype, field, "dummy", ptr_type_node);
!       PUSH_FIELD (ctype, field, "utf8",  utf8const_ptr_type);
!       FINISH_RECORD (ctype);
!       START_RECORD_CONSTRUCTOR (cinit, ctype);
!       PUSH_FIELD_VALUE (cinit, "dummy", 
! 			convert (ptr_type_node, integer_minus_one_node));
!       PUSH_FIELD_VALUE (cinit, "utf8", utf8_ref);
!       FINISH_RECORD_CONSTRUCTOR (cinit);
!       TREE_CONSTANT (cinit) = 1;
!       decl = build_decl (VAR_DECL, get_identifier (buf), ctype);
        TREE_STATIC (decl) = 1;
        DECL_ARTIFICIAL (decl) = 1;
--- 314,352 ----
    tree exp;
  
!   /* The "type" (metch_info) in a (Java) exception table is a pointer tone:
     * a) NULL - meaning match any type in a try-finally.
!    * b) a pointer to pointer to a class.
!    * c) a pointer to pointer to a utf8_ref.  The pointer is rewritten
!    * to point to the appropriate class.  */
  
    if (type == NULL_TREE)
      exp = NULL_TREE;
!   else if (is_compiled_class (type) && !flag_indirect_dispatch)
!     {
!       char buf[64];
!       tree decl;
!       sprintf (buf, "%s_ref", 
! 	       IDENTIFIER_POINTER (DECL_NAME (TYPE_NAME (type))));
!       decl = build_decl (VAR_DECL, get_identifier (buf), ptr_type_node);
!       TREE_STATIC (decl) = 1;
!       DECL_ARTIFICIAL (decl) = 1;
!       DECL_IGNORED_P (decl) = 1;
!       TREE_READONLY (decl) = 1;
!       TREE_THIS_VOLATILE (decl) = 0;
!       DECL_INITIAL (decl) = build_class_ref (type);
!       layout_decl (decl, 0);
!       pushdecl (decl);
!       rest_of_decl_compilation (decl, (char*) 0, global_bindings_p (), 0);
!       make_decl_rtl (decl, (char*) 0);
!       exp = build1 (ADDR_EXPR, ptr_type_node, decl);
!     }
    else
      {
!       tree decl;
        tree utf8_ref = build_utf8_ref (DECL_NAME (TYPE_NAME (type)));
        char buf[64];
        sprintf (buf, "%s_ref", 
  	       IDENTIFIER_POINTER (DECL_NAME (TREE_OPERAND (utf8_ref, 0))));
!       decl = build_decl (VAR_DECL, get_identifier (buf), utf8const_ptr_type);
        TREE_STATIC (decl) = 1;
        DECL_ARTIFICIAL (decl) = 1;
*************** prepare_eh_table_type (tree type)
*** 348,357 ****
        TREE_READONLY (decl) = 1;
        TREE_THIS_VOLATILE (decl) = 0;
-       DECL_INITIAL (decl) = cinit;
        layout_decl (decl, 0);
        pushdecl (decl);
        rest_of_decl_compilation (decl, (char*) 0, global_bindings_p (), 0);
        make_decl_rtl (decl, (char*) 0);
!       exp = build1 (ADDR_EXPR, build_pointer_type (ctype), decl);
      }
    return exp;
--- 354,363 ----
        TREE_READONLY (decl) = 1;
        TREE_THIS_VOLATILE (decl) = 0;
        layout_decl (decl, 0);
        pushdecl (decl);
        rest_of_decl_compilation (decl, (char*) 0, global_bindings_p (), 0);
        make_decl_rtl (decl, (char*) 0);
!       exp = build1 (ADDR_EXPR, build_pointer_type (utf8const_ptr_type), decl);
!       catch_classes = tree_cons (NULL, make_catch_class_record (exp, utf8_ref), catch_classes);
      }
    return exp;
Index: gcc/java/java-tree.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/java/java-tree.h,v
retrieving revision 1.185
diff -c -2 -p -r1.185 java-tree.h
*** gcc/java/java-tree.h	1 Oct 2003 16:22:11 -0000	1.185
--- gcc/java/java-tree.h	22 Oct 2003 17:19:47 -0000
*************** extern int compiling_from_source;
*** 168,171 ****
--- 168,174 ----
  #define atable_syms_decl java_global_trees [JTI_ATABLE_SYMS_DECL]
  
+ #define ctable_decl java_global_trees [JTI_CTABLE_DECL]
+ #define catch_classes java_global_trees [JTI_CATCH_CLASSES]
+ 
  extern int flag_emit_class_files;
  
*************** enum java_tree_index
*** 425,428 ****
--- 428,435 ----
    JTI_ATABLE_SYMS_DECL,
  
+   JTI_CTABLE_DECL,
+   JTI_CATCH_CLASSES,
+ 
+ 
    JTI_PREDEF_FILENAMES,
  
*************** extern GTY(()) tree java_global_trees[JT
*** 630,633 ****
--- 637,642 ----
  #define symbols_array_ptr_type \
    java_global_trees[JTI_SYMBOLS_ARRAY_PTR_TYPE]
+ #define class_refs_decl \
+   Jjava_global_trees[TI_CLASS_REFS_DECL]
  
  #define end_params_node \
*************** extern void java_expand_body (tree);
*** 1321,1324 ****
--- 1330,1338 ----
  extern int get_symbol_table_index (tree, tree *);
  
+ extern tree make_catch_class_record (tree, tree);
+ extern void emit_catch_table (void);
+ 
+ 
+ 
  #define DECL_FINAL(DECL) DECL_LANG_FLAG_3 (DECL)
  
*************** extern tree *type_map;
*** 1679,1687 ****
     NAME is a char* string used for error checking;
     the initializer must be specified in order. */
!   #define PUSH_FIELD_VALUE(CONS, NAME, VALUE) {\
!     tree field = TREE_CHAIN(CONS);\
!     if (strcmp (IDENTIFIER_POINTER (DECL_NAME (field)), NAME) != 0) abort();\
!     CONSTRUCTOR_ELTS(CONS) = tree_cons (field, VALUE, CONSTRUCTOR_ELTS(CONS));\
!     TREE_CHAIN(CONS) = TREE_CHAIN (field); }
  
  /* Finish creating a record CONSTRUCTOR CONS. */
--- 1693,1706 ----
     NAME is a char* string used for error checking;
     the initializer must be specified in order. */
! #define PUSH_FIELD_VALUE(CONS, NAME, VALUE) 					\
! do										\
! {										\
!   tree field = TREE_CHAIN(CONS);						\
!   if (strcmp (IDENTIFIER_POINTER (DECL_NAME (field)), NAME) != 0) 		\
!     abort();									\
!   CONSTRUCTOR_ELTS(CONS) = tree_cons (field, VALUE, CONSTRUCTOR_ELTS(CONS));	\
!   TREE_CHAIN(CONS) = TREE_CHAIN (field); 					\
! }										\
! while (0)
  
  /* Finish creating a record CONSTRUCTOR CONS. */
Index: gcc/java/jcf-parse.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/java/jcf-parse.c,v
retrieving revision 1.148
diff -c -2 -p -r1.148 jcf-parse.c
*** gcc/java/jcf-parse.c	1 Oct 2003 16:22:11 -0000	1.148
--- gcc/java/jcf-parse.c	22 Oct 2003 17:19:47 -0000
*************** java_parse_file (int set_yydebug ATTRIBU
*** 1138,1141 ****
--- 1138,1142 ----
  	     atable_decl, atable_methods, atable_syms_decl, ptr_type_node);
  	}
+       emit_catch_table ();
      }
  
Index: gcc/java/lang.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/java/lang.c,v
retrieving revision 1.143
diff -c -2 -p -r1.143 lang.c
*** gcc/java/lang.c	28 Sep 2003 04:56:34 -0000	1.143
--- gcc/java/lang.c	22 Oct 2003 17:19:48 -0000
*************** static bool java_decl_ok_for_sibcall (tr
*** 69,72 ****
--- 69,73 ----
  static int java_estimate_num_insns (tree);
  static int java_start_inlining (tree);
+ static tree java_get_callee_fndecl (tree);
  
  #ifndef TARGET_OBJECT_SUFFIX
*************** struct language_function GTY(())
*** 264,267 ****
--- 265,271 ----
  #define LANG_HOOKS_DECL_OK_FOR_SIBCALL java_decl_ok_for_sibcall
  
+ #undef LANG_HOOKS_GET_CALLEE_FNDECL
+ #define LANG_HOOKS_GET_CALLEE_FNDECL java_get_callee_fndecl
+ 
  #undef LANG_HOOKS_CALLGRAPH_EXPAND_FUNCTION
  #define LANG_HOOKS_CALLGRAPH_EXPAND_FUNCTION java_expand_body
*************** java_start_inlining (tree fn)
*** 1204,1207 ****
--- 1208,1252 ----
       that are not yet expanded.  */
    return TREE_ASM_WRITTEN (fn) ? 1 : 0;
+ }
+ 
+ /* Given a call_expr, try to figure out what its target might be.  In
+    the case of an indirection via the atable, search for the decl.  If
+    the decl is external, we return NULL.  If we don't, the optimizer
+    will replace the indirection with a direct call, which undoes the
+    purpose of the atable indirection.  */
+ static tree
+ java_get_callee_fndecl (tree call_expr)
+ {
+   tree method, table, element;
+ 
+   HOST_WIDE_INT index;
+ 
+   if (TREE_CODE (call_expr) != CALL_EXPR)
+     return NULL;
+   method = TREE_OPERAND (call_expr, 0);
+   STRIP_NOPS (method);
+   if (TREE_CODE (method) != ARRAY_REF)
+     return NULL;
+   table = TREE_OPERAND (method, 0);
+   if (table != atable_decl)
+     return NULL;
+   index = TREE_INT_CST_LOW (TREE_OPERAND (method, 1));
+ 
+   /* FIXME: Replace this for loop with a hash table lookup.  */
+   for (element = atable_methods; element; element = TREE_CHAIN (element))
+     {
+       if (index == 1)
+ 	{
+ 	  tree purpose = TREE_PURPOSE (element);
+ 	  if (TREE_CODE (purpose) == FUNCTION_DECL
+ 	      && ! DECL_EXTERNAL (purpose))
+ 	    return purpose;
+ 	  else
+ 	    return NULL;
+ 	}
+       --index;
+     }
+   
+   return NULL;
  }
  
Index: libjava/defineclass.cc
===================================================================
RCS file: /cvs/gcc/gcc/libjava/defineclass.cc,v
retrieving revision 1.34
diff -c -2 -p -r1.34 defineclass.cc
*** libjava/defineclass.cc	29 Jul 2003 17:12:54 -0000	1.34
--- libjava/defineclass.cc	22 Oct 2003 17:19:54 -0000
*************** void _Jv_ClassReader::handleCodeAttribut
*** 1271,1274 ****
--- 1271,1275 ----
      (_Jv_InterpMethod*) (_Jv_AllocBytes (size));
  
+   method->deferred	 = NULL;
    method->max_stack      = max_stack;
    method->max_locals     = max_locals;
*************** void _Jv_ClassReader::handleMethodsEnd (
*** 1329,1332 ****
--- 1330,1334 ----
  	      m->function = NULL;
  	      def->interpreted_methods[i] = m;
+ 	      m->deferred = NULL;
  
  	      if ((method->accflags & Modifier::STATIC))
Index: libjava/exception.cc
===================================================================
RCS file: /cvs/gcc/gcc/libjava/exception.cc,v
retrieving revision 1.23
diff -c -2 -p -r1.23 exception.cc
*** libjava/exception.cc	20 Aug 2003 17:27:55 -0000	1.23
--- libjava/exception.cc	22 Oct 2003 17:19:54 -0000
*************** parse_lsda_header (_Unwind_Context *cont
*** 162,166 ****
  }
  
! static jclass
  get_ttype_entry (_Unwind_Context *context, lsda_header_info *info, long i)
  {
--- 162,166 ----
  }
  
! static void **
  get_ttype_entry (_Unwind_Context *context, lsda_header_info *info, long i)
  {
*************** get_ttype_entry (_Unwind_Context *contex
*** 170,174 ****
    read_encoded_value (context, info->ttype_encoding, info->TType - i, &ptr);
  
!   return reinterpret_cast<jclass>(ptr);
  }
  
--- 170,174 ----
    read_encoded_value (context, info->ttype_encoding, info->TType - i, &ptr);
  
!   return reinterpret_cast<void **>(ptr);
  }
  
*************** PERSONALITY_FUNCTION (int version,
*** 337,357 ****
  	      // Positive filter values are handlers.
  
! 	      jclass catch_type = get_ttype_entry (context, &info, ar_filter);
  
- 	      typedef struct {
- 		int __attribute__ ((mode (pointer))) dummy; 
- 		Utf8Const *utf8;
- 	      } utf8_hdr;
- 	      utf8_hdr *p = (utf8_hdr *)catch_type;
- 	      if (p->dummy == -1)
- 		{
- 		  using namespace gnu::gcj::runtime;
- 		  java::lang::Class *klass 
- 		    = StackTrace::getClass ((gnu::gcj::RawData *)ip);
- 		  java::lang::ClassLoader *loader 
- 		    = klass ? klass->getClassLoaderInternal () : NULL;
- 		  catch_type = _Jv_FindClass (p->utf8, loader);
- 		}
- 	      
  	      if (_Jv_IsInstanceOf (xh->value, catch_type))
  		{
--- 337,349 ----
  	      // Positive filter values are handlers.
  
! 	      void **catch_word = get_ttype_entry (context, &info, ar_filter);
! 	      jclass catch_type = (jclass)*catch_word;
! 
! 	      // FIXME: This line is a kludge to work around exception
! 	      // handlers written in C++, which don't yet use indirect
! 	      // dispatch.
! 	      if (catch_type == *(void **)&java::lang::Class::class$)
! 		catch_type = (jclass)catch_word;
  
  	      if (_Jv_IsInstanceOf (xh->value, catch_type))
  		{
Index: libjava/resolve.cc
===================================================================
RCS file: /cvs/gcc/gcc/libjava/resolve.cc,v
retrieving revision 1.42
diff -c -2 -p -r1.42 resolve.cc
*** libjava/resolve.cc	25 Sep 2003 07:46:18 -0000	1.42
--- libjava/resolve.cc	22 Oct 2003 17:19:55 -0000
*************** _Jv_PrepareClass(jclass klass)
*** 576,579 ****
--- 576,589 ----
  	  _Jv_VerifyMethod (im);
  	  clz->methods[i].ncode = im->ncode ();
+ 
+ 	  // Resolve ctable entries pointing to this method.  See
+ 	  // _Jv_Defer_Resolution.
+ 	  void **code = (void **)imeth->deferred;
+ 	  while (code)
+ 	    {
+ 	      void **target = (void **)*code;
+ 	      *code = clz->methods[i].ncode;
+ 	      code = target;
+ 	    }
  	}
      }
Index: libjava/include/java-interp.h
===================================================================
RCS file: /cvs/gcc/gcc/libjava/include/java-interp.h,v
retrieving revision 1.22
diff -c -2 -p -r1.22 java-interp.h
*** libjava/include/java-interp.h	24 Jan 2003 19:58:21 -0000	1.22
--- libjava/include/java-interp.h	22 Oct 2003 17:19:55 -0000
*************** protected:
*** 89,92 ****
--- 89,98 ----
    _Jv_ushort args_raw_size;
  
+   // Chain of addresses to fill in.  See _Jv_Defer_Resolution.
+   void *deferred;
+ 
+   friend void _Jv_Defer_Resolution (void *cl, _Jv_Method *meth, void **);
+   friend void _Jv_PrepareClass(jclass);
+ 
  public:
    _Jv_Method *get_method ()
*************** class _Jv_InterpClass : public java::lan
*** 168,172 ****
--- 174,203 ----
  
    friend _Jv_MethodBase ** _Jv_GetFirstMethod (_Jv_InterpClass *klass);
+   friend void _Jv_Defer_Resolution (void *cl, _Jv_Method *meth, void **);
  };
+ 
+ // We have an interpreted class CL and we're trying to find the
+ // address of the ncode of a method METH.  That interpreted class
+ // hasn't yet been prepared, so we defer fixups until they are ready.
+ // To do this, we create a chain of fixups that will be resolved by
+ // _Jv_PrepareClass.
+ extern inline void 
+ _Jv_Defer_Resolution (void *cl, _Jv_Method *meth, void **address)
+ {
+   int i;
+   _Jv_InterpClass *self = (_Jv_InterpClass *)cl;
+   for (i = 0; i < self->method_count; i++)
+     {
+       _Jv_Method *m = &self->methods[i];
+       if (m == meth)
+ 	{
+ 	  _Jv_MethodBase *imeth = self->interpreted_methods[i];
+ 	  *address = imeth->deferred;
+ 	  imeth->deferred = address;
+ 	  return;
+ 	}
+     }
+   return;
+ }    
  
  extern inline _Jv_MethodBase **
Index: libjava/java/lang/Class.h
===================================================================
RCS file: /cvs/gcc/gcc/libjava/java/lang/Class.h,v
retrieving revision 1.60
diff -c -2 -p -r1.60 Class.h
*** libjava/java/lang/Class.h	9 Oct 2003 16:24:55 -0000	1.60
--- libjava/java/lang/Class.h	22 Oct 2003 17:19:55 -0000
*************** struct _Jv_AddressTable
*** 132,135 ****
--- 132,141 ----
  };
  
+ struct _Jv_CatchClass
+ {
+   java::lang::Class **address;
+   _Jv_Utf8Const *classname;
+ };
+ 
  #define JV_PRIMITIVE_VTABLE ((_Jv_VTable *) -1)
  
*************** private:   
*** 336,339 ****
--- 342,346 ----
    friend void _Jv_SetVTableEntries (jclass, _Jv_VTable *, jboolean *);
    friend void _Jv_MakeVTable (jclass);
+   friend void _Jv_linkExceptionClassTable (jclass);
  
    friend jboolean _Jv_CheckAccess (jclass self_klass, jclass other_klass,
*************** private:   
*** 365,368 ****
--- 372,377 ----
    friend void _Jv_PrepareMissingMethods (jclass base, jclass iface_class);
  
+   friend void _Jv_Defer_Resolution (void *cl, _Jv_Method *meth, void **);
+   
    friend class _Jv_ClassReader;	
    friend class _Jv_InterpClass;
*************** private:   
*** 414,417 ****
--- 423,427 ----
    _Jv_AddressTable *atable;
    _Jv_MethodSymbol *atable_syms;
+   _Jv_CatchClass *catch_classes;
    // Interfaces implemented by this class.
    jclass *interfaces;
Index: libjava/java/lang/natClass.cc
===================================================================
RCS file: /cvs/gcc/gcc/libjava/java/lang/natClass.cc,v
retrieving revision 1.66
diff -c -2 -p -r1.66 natClass.cc
*** libjava/java/lang/natClass.cc	9 Oct 2003 16:24:55 -0000	1.66
--- libjava/java/lang/natClass.cc	22 Oct 2003 17:19:56 -0000
*************** details.  */
*** 13,16 ****
--- 13,17 ----
  #include <limits.h>
  #include <string.h>
+ #include <stddef.h>
  
  #pragma implementation "Class.h"
*************** details.  */
*** 57,61 ****
  
  #include <java-cpool.h>
! 
  
  
--- 58,62 ----
  
  #include <java-cpool.h>
! #include <java-interp.h>
  
  
*************** java::lang::Class::initializeClass (void
*** 835,838 ****
--- 836,841 ----
      _Jv_LinkSymbolTable(this);
  
+   _Jv_linkExceptionClassTable (this);
+ 
    // Steps 8, 9, 10, 11.
    try
*************** _Jv_LinkSymbolTable(jclass klass)
*** 1580,1583 ****
--- 1583,1587 ----
    for (index = 0; sym = klass->otable_syms[index], sym.name != NULL; index++)
      {
+       // FIXME: Why are we passing NULL as the class loader?
        jclass target_class = _Jv_FindClass (sym.class_name, NULL);
        _Jv_Method *meth = NULL;            
*************** _Jv_LinkSymbolTable(jclass klass)
*** 1585,1591 ****
        const _Jv_Utf8Const *signature = sym.signature;
  
!       // FIXME: This should be special index for ThrowNoSuchMethod().
!       klass->otable->offsets[index] = -1;
!       
        if (target_class == NULL)
  	continue;
--- 1589,1598 ----
        const _Jv_Utf8Const *signature = sym.signature;
  
!       {
! 	static char *bounce = (char *)_Jv_ThrowNoSuchMethodError;
! 	ptrdiff_t offset = (char *)(klass->vtable) - bounce;
! 	klass->otable->offsets[index] = offset;
!       }
! 
        if (target_class == NULL)
  	continue;
*************** _Jv_LinkSymbolTable(jclass klass)
*** 1697,1700 ****
--- 1704,1708 ----
    for (index = 0; sym = klass->atable_syms[index], sym.name != NULL; index++)
      {
+       // FIXME: Why are we passing NULL as the class loader?
        jclass target_class = _Jv_FindClass (sym.class_name, NULL);
        _Jv_Method *meth = NULL;            
*************** _Jv_LinkSymbolTable(jclass klass)
*** 1726,1730 ****
  	  
  	  if (meth != NULL)
! 	    klass->atable->addresses[index] = meth->ncode;
  	  else
  	    klass->atable->addresses[index] = (void *)_Jv_ThrowNoSuchMethodError;
--- 1734,1744 ----
  	  
  	  if (meth != NULL)
! 	    {
! 	      if (meth->ncode) // Maybe abstract?
! 		klass->atable->addresses[index] = meth->ncode;
! 	      else if (_Jv_IsInterpretedClass (target_class))
! 		_Jv_Defer_Resolution (target_class, meth, 
! 				      &klass->atable->addresses[index]);
! 	    }
  	  else
  	    klass->atable->addresses[index] = (void *)_Jv_ThrowNoSuchMethodError;
*************** _Jv_LinkSymbolTable(jclass klass)
*** 1782,1785 ****
--- 1796,1820 ----
  }
  
+ 
+ // For each catch_record in the list of caught classes, fill in the
+ // address field.
+ void 
+ _Jv_linkExceptionClassTable (jclass self)
+ {
+   struct _Jv_CatchClass *catch_record = self->catch_classes;
+   if (!catch_record || catch_record->classname)
+     return;  
+   catch_record++;
+   while (catch_record->classname)
+     {
+       jclass target_class = _Jv_FindClass (catch_record->classname,  
+ 					   self->getClassLoaderInternal ());
+       *catch_record->address = target_class;
+       catch_record++;
+     }
+   self->catch_classes->classname = (_Jv_Utf8Const *)-1;
+ }
+   
+ 
  // Returns true if METH should get an entry in a VTable.
  static jboolean
*************** _Jv_LayoutVTableMethods (jclass klass)
*** 1810,1813 ****
--- 1845,1868 ----
  
    jclass superclass = klass->superclass;
+ 
+   typedef unsigned int uaddr __attribute__ ((mode (pointer)));
+ 
+   // If superclass looks like a constant pool entry,
+   // resolve it now.
+   if ((uaddr)superclass < (uaddr)klass->constants.size)
+     {
+       if (klass->state < JV_STATE_LINKED)
+ 	{
+ 	  _Jv_Utf8Const *name = klass->constants.data[(int)superclass].utf8;
+ 	  superclass = _Jv_FindClass (name, klass->loader);
+ 	  if (! superclass)
+ 	    {
+ 	      jstring str = _Jv_NewStringUTF (name->data);
+ 	      throw new java::lang::NoClassDefFoundError (str);
+ 	    }
+ 	}
+       else
+ 	superclass = klass->constants.data[(int)superclass].clazz;
+     }
  
    if (superclass != NULL && superclass->vtable_method_count == -1)



More information about the Java-patches mailing list