lang.c (LANG_HOOKS_GET_CALLEE_FNDECL): New.
authorAndrew Haley <aph@redhat.com>
Fri, 24 Oct 2003 09:29:43 +0000 (09:29 +0000)
committerAndrew Haley <aph@gcc.gnu.org>
Fri, 24 Oct 2003 09:29:43 +0000 (09:29 +0000)
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.

From-SVN: r72886

14 files changed:
gcc/java/ChangeLog
gcc/java/class.c
gcc/java/decl.c
gcc/java/except.c
gcc/java/java-tree.h
gcc/java/jcf-parse.c
gcc/java/lang.c
libjava/ChangeLog
libjava/defineclass.cc
libjava/exception.cc
libjava/include/java-interp.h
libjava/java/lang/Class.h
libjava/java/lang/natClass.cc
libjava/resolve.cc

index 16bb5135d565c19b3335a92f772af8d3c39d7b00..1458560aad1fb71c97f92aecccfe099b6f23d304 100644 (file)
@@ -1,3 +1,28 @@
+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  Kazu Hirata  <kazu@cs.umass.edu>
 
        * jcf-write.c: Follow spelling conventions.
index 49e1a3db5cf4e0a6c3d848b4795c75c9fd85f742..2aacbd42e041461f2814b208a9a83d5614b44f96 100644 (file)
@@ -808,6 +808,20 @@ build_utf8_ref (tree name)
   return ref;
 }
 
+/* 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. */
 
@@ -820,6 +834,12 @@ build_class_ref (tree type)
       tree ref, decl_name, decl;
       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)
        {
          if (TYPE_SIZE (type) == error_mark_node)
@@ -902,14 +922,7 @@ build_class_ref (tree type)
       return ref;
     }
   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;
-    }
+    return build_indirect_class_ref (type);
 }
 
 tree
@@ -1061,7 +1074,7 @@ make_field_value (tree fdecl)
   tree finit;
   int flags;
   tree type = TREE_TYPE (fdecl);
-  int resolved = is_compiled_class (type);
+  int resolved = is_compiled_class (type) && ! flag_indirect_dispatch;
 
   START_RECORD_CONSTRUCTOR (finit, field_type_node);
   PUSH_FIELD_VALUE (finit, "name", build_utf8_ref (DECL_NAME (fdecl)));
@@ -1422,7 +1435,8 @@ make_class_data (tree type)
   super = CLASSTYPE_SUPER (type);
   if (super == NULL_TREE)
     super = null_pointer_node;
-  else if (assume_compiled (IDENTIFIER_POINTER (DECL_NAME (type_decl)))
+  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);
   else
@@ -1492,7 +1506,7 @@ make_class_data (tree type)
   PUSH_FIELD_VALUE (cons, "method_count",  build_int_2 (method_count, 0));
 
   if (flag_indirect_dispatch)
-    PUSH_FIELD_VALUE (cons, "vtable_method_count", integer_minus_one_node)
+    PUSH_FIELD_VALUE (cons, "vtable_method_count", integer_minus_one_node);
   else
     PUSH_FIELD_VALUE (cons, "vtable_method_count", TYPE_NVIRTUALS (type));
     
@@ -1505,7 +1519,7 @@ make_class_data (tree type)
                    build_int_2 (static_field_count, 0));
 
   if (flag_indirect_dispatch)
-    PUSH_FIELD_VALUE (cons, "vtable", null_pointer_node)
+    PUSH_FIELD_VALUE (cons, "vtable", null_pointer_node);
   else
     PUSH_FIELD_VALUE (cons, "vtable",
                      dtable_decl == NULL_TREE ? null_pointer_node
@@ -1540,7 +1554,9 @@ make_class_data (tree type)
                                atable_syms_decl));
       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);
   PUSH_FIELD_VALUE (cons, "interface_count", build_int_2 (interface_len, 0));
@@ -2210,6 +2226,47 @@ emit_symbol_table (tree name, tree the_table, tree decl_list, tree the_syms_decl
   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
 init_class_processing (void)
 {
index fa8c939cd47780dea6b13d9f97f2fafe1b3194c6..e23cb120c3a86613e63ba4ea8a3cb92cf1d0b120 100644 (file)
@@ -663,6 +663,23 @@ java_init_decl_processing (void)
       pushdecl (atable_syms_decl);
     }
   
+  {  
+    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.
      There is an unresolved issue here, which is whether the vtable
@@ -702,6 +719,7 @@ java_init_decl_processing (void)
   PUSH_FIELD (class_type_node, field, "atable", atable_ptr_type);
   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));
   PUSH_FIELD (class_type_node, field, "loader", ptr_type_node);
index 6aeff65ea259461684177c6708c075a503dbef16..dc97b42fabff5003d509e780ffa06b4f2fd502ae 100644 (file)
@@ -313,46 +313,52 @@ prepare_eh_table_type (tree type)
 {
   tree exp;
 
-  /* The "type" (metch_info) in a (Java) exception table is one:
+  /* The "type" (match_info) in a (Java) exception table is a pointer to:
    * 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). */
+   * b) a pointer to a pointer to a class.
+   * c) a pointer to a 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))
-    exp = build_class_ref (type);
+  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 ctype = make_node (RECORD_TYPE);
-      tree field = NULL_TREE;
-      tree cinit, decl;
+      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))));
-      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);
+      decl = build_decl (VAR_DECL, get_identifier (buf), utf8const_ptr_type);
       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) = 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);
+      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 42f99b57e95c71eb6eceff3a84b6584f92b8d0b2..7b5a397ecdbbd5bab909d8200b03b5687c095b2b 100644 (file)
@@ -167,6 +167,9 @@ extern int compiling_from_source;
    otable. */
 #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;
 
 extern int flag_filelist_file;
@@ -424,6 +427,9 @@ enum java_tree_index
   JTI_ATABLE_DECL,
   JTI_ATABLE_SYMS_DECL,
 
+  JTI_CTABLE_DECL,
+  JTI_CATCH_CLASSES,
+
   JTI_PREDEF_FILENAMES,
 
   JTI_MAX
@@ -629,6 +635,8 @@ extern GTY(()) tree java_global_trees[JTI_MAX];
   java_global_trees[JTI_SYMBOLS_ARRAY_TYPE]
 #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 \
   java_global_trees[JTI_END_PARAMS_NODE]
@@ -1320,6 +1328,9 @@ extern void java_expand_body (tree);
 
 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)
 
 /* Access flags etc for a method (a FUNCTION_DECL): */
@@ -1678,11 +1689,16 @@ extern tree *type_map;
 /* Append a field initializer to CONS for a field with the given VALUE.
    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); }
+#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. */
 #define FINISH_RECORD_CONSTRUCTOR(CONS) \
index de4b213a6c68bc83bbff00a81c6b94cd30668bb4..7570f8612485e883b4c89b6d2a6f0aa2c022b531 100644 (file)
@@ -632,7 +632,7 @@ jcf_parse (JCF* jcf)
   if (CLASS_PARSED_P (current_class))
     {
       /* FIXME - where was first time */
-      fatal_error ("reading class %s for the second time from %s",
+      fatal_error (stderr, "READING CLASS %s for the second time from %s",
                   IDENTIFIER_POINTER (DECL_NAME (TYPE_NAME (current_class))),
                   jcf->filename);
     }
@@ -1137,6 +1137,7 @@ java_parse_file (int set_yydebug ATTRIBUTE_UNUSED)
            (get_identifier ("atable"), 
             atable_decl, atable_methods, atable_syms_decl, ptr_type_node);
        }
+      emit_catch_table ();
     }
 
   write_resource_constructor ();
index ee476b2fc9e524f6c2ba72c39e1b4ba7c5944b8c..615d250c0187c1722f59ff2f813fd7419e98c44e 100644 (file)
@@ -68,6 +68,7 @@ static void dump_compound_expr (dump_info_p, tree);
 static bool java_decl_ok_for_sibcall (tree);
 static int java_estimate_num_insns (tree);
 static int java_start_inlining (tree);
+static tree java_get_callee_fndecl (tree);
 
 #ifndef TARGET_OBJECT_SUFFIX
 # define TARGET_OBJECT_SUFFIX ".o"
@@ -263,6 +264,9 @@ struct language_function GTY(())
 #undef LANG_HOOKS_DECL_OK_FOR_SIBCALL
 #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
 
@@ -1205,4 +1209,45 @@ java_start_inlining (tree fn)
   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;
+}
+
 #include "gt-java-lang.h"
index 742e94b036cbc4e171aa0f3dba1f9548e8023f04..72b4d6cb6476651d9304270b671dd49895ac44a7 100644 (file)
@@ -1,3 +1,29 @@
+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.
+
 2003-10-23  Rainer Orth  <ro@TechFak.Uni-Bielefeld.DE>
 
        * java/lang/natObject.cc (_Jv_ObjectCheckMonitor): Use
index 4cd4f4f1936bc541c73e567fc57014645a8db671..2e8b4d974346d70810888359267de59454ca821b 100644 (file)
@@ -1270,6 +1270,7 @@ void _Jv_ClassReader::handleCodeAttribute
   _Jv_InterpMethod *method = 
     (_Jv_InterpMethod*) (_Jv_AllocBytes (size));
 
+  method->deferred      = NULL;
   method->max_stack      = max_stack;
   method->max_locals     = max_locals;
   method->code_length    = code_length;
@@ -1328,6 +1329,7 @@ void _Jv_ClassReader::handleMethodsEnd ()
              m->self = method;
              m->function = NULL;
              def->interpreted_methods[i] = m;
+             m->deferred = NULL;
 
              if ((method->accflags & Modifier::STATIC))
                {
index 9647d446d18ecdf24ae0ad3c7c926635c3cfdbf8..088d48268e3da54e7749bce020f9e95379e11f2d 100644 (file)
@@ -161,7 +161,7 @@ parse_lsda_header (_Unwind_Context *context, const unsigned char *p,
   return p;
 }
 
-static jclass
+static void **
 get_ttype_entry (_Unwind_Context *context, lsda_header_info *info, long i)
 {
   _Unwind_Ptr ptr;
@@ -169,7 +169,7 @@ get_ttype_entry (_Unwind_Context *context, lsda_header_info *info, long i)
   i *= size_of_encoded_value (info->ttype_encoding);
   read_encoded_value (context, info->ttype_encoding, info->TType - i, &ptr);
 
-  return reinterpret_cast<jclass>(ptr);
+  return reinterpret_cast<void **>(ptr);
 }
 
 
@@ -336,23 +336,15 @@ PERSONALITY_FUNCTION (int version,
            {
              // Positive filter values are handlers.
 
-             jclass catch_type = get_ttype_entry (context, &info, ar_filter);
+             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;
 
-             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))
                {
                  handler_switch_value = ar_filter;
index c801274f4cbf69fa053f33c257319199c5d0a478..94acfae281f40facb02abd13a34b871f07695791 100644 (file)
@@ -88,6 +88,12 @@ protected:
   // Size of raw arguments.
   _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 ()
   {
@@ -167,8 +173,33 @@ class _Jv_InterpClass : public java::lang::Class
 #endif
 
   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 **
 _Jv_GetFirstMethod (_Jv_InterpClass *klass)
 {
index cdfdd7d2349bb39284f09e86fcd7b1d334178bc1..01761af5cec06dd2c1b4ac25d68ed47bc9594dde 100644 (file)
@@ -131,6 +131,12 @@ struct _Jv_AddressTable
   void *addresses[];
 };
 
+struct _Jv_CatchClass
+{
+  java::lang::Class **address;
+  _Jv_Utf8Const *classname;
+};
+
 #define JV_PRIMITIVE_VTABLE ((_Jv_VTable *) -1)
 
 #define JV_CLASS(Obj) ((jclass) (*(_Jv_VTable **) Obj)->clas)
@@ -336,6 +342,7 @@ private:
   friend void _Jv_LayoutVTableMethods (jclass klass);
   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,
                                   jint flags);
@@ -365,6 +372,8 @@ private:
   friend void _Jv_PrepareClass (jclass);
   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;
   friend class _Jv_InterpMethod;
@@ -414,6 +423,7 @@ private:
   _Jv_MethodSymbol *otable_syms;
   _Jv_AddressTable *atable;
   _Jv_MethodSymbol *atable_syms;
+  _Jv_CatchClass *catch_classes;
   // Interfaces implemented by this class.
   jclass *interfaces;
   // The class loader for this class.
index c9b70147b6181e24c19b997f6f8e79bc3791378a..2d80ce2133b49a9cd4392a18bef95d38488b6a51 100644 (file)
@@ -12,6 +12,7 @@ details.  */
 
 #include <limits.h>
 #include <string.h>
+#include <stddef.h>
 
 #pragma implementation "Class.h"
 
@@ -56,7 +57,7 @@ details.  */
 #include <gnu/gcj/RawData.h>
 
 #include <java-cpool.h>
-
+#include <java-interp.h>
 \f
 
 using namespace gcj;
@@ -796,6 +797,8 @@ java::lang::Class::initializeClass (void)
   if (otable || atable)
     _Jv_LinkSymbolTable(this);
 
+  _Jv_linkExceptionClassTable (this);
+
   // Steps 8, 9, 10, 11.
   try
     {
@@ -1541,14 +1544,18 @@ _Jv_LinkSymbolTable(jclass klass)
 
   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;            
 
       const _Jv_Utf8Const *signature = sym.signature;
 
-      // FIXME: This should be special index for ThrowNoSuchMethod().
-      klass->otable->offsets[index] = -1;
-      
+      {
+       static char *bounce = (char *)_Jv_ThrowNoSuchMethodError;
+       ptrdiff_t offset = (char *)(klass->vtable) - bounce;
+       klass->otable->offsets[index] = offset;
+      }
+
       if (target_class == NULL)
        continue;
 
@@ -1658,6 +1665,7 @@ _Jv_LinkSymbolTable(jclass klass)
 
   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;            
       const _Jv_Utf8Const *signature = sym.signature;
@@ -1687,7 +1695,13 @@ _Jv_LinkSymbolTable(jclass klass)
                                          sym.signature);
          
          if (meth != NULL)
-           klass->atable->addresses[index] = meth->ncode;
+           {
+             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;
 
@@ -1743,6 +1757,27 @@ _Jv_LinkSymbolTable(jclass klass)
     }
 }
 
+
+// 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
 isVirtualMethod (_Jv_Method *meth)
@@ -1772,6 +1807,26 @@ _Jv_LayoutVTableMethods (jclass klass)
 
   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)
     {
       JvSynchronize sync (superclass);
index ce1af8d2586e22e089c33977c8bc68cdf5d10f70..d71e1251ff0946a7ad5aac730819f77816cb7b4f 100644 (file)
@@ -575,6 +575,16 @@ _Jv_PrepareClass(jclass klass)
          _Jv_InterpMethod *im = reinterpret_cast<_Jv_InterpMethod *> (imeth);
          _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;
+           }
        }
     }