java-tree.h (otable_methods, [...]): New field/global tree definitions.
authorBryce McKinlay <bryce@waitaki.otago.ac.nz>
Sat, 15 Dec 2001 08:31:49 +0000 (08:31 +0000)
committerBryce McKinlay <bryce@gcc.gnu.org>
Sat, 15 Dec 2001 08:31:49 +0000 (08:31 +0000)
gcc/java:

* java-tree.h (otable_methods, otable_decl, otable_syms_decl,
otable_type, otable_ptr_type, method_symbol_type,
method_symbols_array_type, method_symbols_array_ptr_type): New
field/global tree definitions.
(flag_indirect_dispatch): New flag.
* decl.c (java_init_decl_processing): Initialize new otable and
otable_syms type nodes and decls. Add new field "index" to
method_type_node.
* class.c (build_method_symbols_entry): New function.
(make_method_value): Set "index" to to method's vtable index for
virtual methods when indirect-dispatch is not used.
(make_class_data): For indirect-dispatch, dont emit the dtable_decl,
and set vtable_method_count to -1. Set otable and otable_syms field
if indirect-dispatch is used and there was something to put in them.
(build_method_symbols_entry): New function.
(emit_offset_symbol_table): New function.
* expr.c (get_offset_table_index): New function.
(build_invokevirtual): Build array reference to otable at the index
returned by get_offset_table_index, and use the result as the vtable
offset.
(build_invokeinterface): Similar.
* jcf-parse.c (yyparse): If indirect-dispatch, call
emit_offset_symbol_table at the end of compilation, after all classes
have been generated.
* jvspec.c: Don't pass findirect-dispatch to jvgenmain.
* lang.c (flag_indirect_dispatch): Define.
(lang_f_options): Add indirect-dispatch flag.

libjava:

* include/jvm.h (_Jv_VTable::idx_to_offset): New method.
* java/lang/natClassLoader.cc (_Jv_PrepareCompiledClass): Call
_Jv_MakeVTable and _Jv_LinkOffsetTable if needed.
* java/lang/Class.h (_Jv_Method): Add "index" field.
(_Jv_MethodSymbol): New struct type.
(_Jv_LinkOffsetTable, _Jv_LayoutVTableMethods, _Jv_SetVTableEntries,
_Jv_MakeVTable): Friends.
(otable, otable_syms): New Class fields.
* java/lang/natClass.cc (_Jv_LinkOffsetTable): New function.
(isVirtualMethod): New static function.
(_Jv_LayoutVTableMethods): New function.
(_Jv_SetVTableEntries): New function.
(_Jv_MakeVTable): New function.

From-SVN: r48038

13 files changed:
gcc/java/ChangeLog
gcc/java/class.c
gcc/java/decl.c
gcc/java/expr.c
gcc/java/java-tree.h
gcc/java/jcf-parse.c
gcc/java/jvspec.c
gcc/java/lang.c
libjava/ChangeLog
libjava/include/jvm.h
libjava/java/lang/Class.h
libjava/java/lang/natClass.cc
libjava/java/lang/natClassLoader.cc

index 192b6bc104d9c4f772b750509a97ae7082627678..46e3e57db6c7d732285c528e5381b92825cbfcd3 100644 (file)
@@ -1,3 +1,33 @@
+2001-12-15  Bryce McKinlay  <bryce@waitaki.otago.ac.nz>
+
+       * java-tree.h (otable_methods, otable_decl, otable_syms_decl,
+       otable_type, otable_ptr_type, method_symbol_type, 
+       method_symbols_array_type, method_symbols_array_ptr_type): New
+       field/global tree definitions.
+       (flag_indirect_dispatch): New flag.
+       * decl.c (java_init_decl_processing): Initialize new otable and 
+       otable_syms type nodes and decls. Add new field "index" to
+       method_type_node.
+       * class.c (build_method_symbols_entry): New function.
+       (make_method_value): Set "index" to to method's vtable index for
+       virtual methods when indirect-dispatch is not used.
+       (make_class_data): For indirect-dispatch, dont emit the dtable_decl,
+       and set vtable_method_count to -1. Set otable and otable_syms field
+       if indirect-dispatch is used and there was something to put in them.
+       (build_method_symbols_entry): New function.
+       (emit_offset_symbol_table): New function.
+       * expr.c (get_offset_table_index): New function.
+       (build_invokevirtual): Build array reference to otable at the index 
+       returned by get_offset_table_index, and use the result as the vtable
+       offset.
+       (build_invokeinterface): Similar.
+       * jcf-parse.c (yyparse): If indirect-dispatch, call 
+       emit_offset_symbol_table at the end of compilation, after all classes 
+       have been generated.
+       * jvspec.c: Don't pass findirect-dispatch to jvgenmain.
+       * lang.c (flag_indirect_dispatch): Define.
+       (lang_f_options): Add indirect-dispatch flag.
+
 2001-12-14  Matthias Klose  <doko@debian.org>
 
        * gcj.texi: Markup for man page generation. Document missing
index 5695aba3e40008305930d6a3abe7870c8e3a560c..6b05435c11e2d84388cee5bf21bfdb4a71dca8fe 100644 (file)
@@ -58,6 +58,8 @@ static int assume_compiled PARAMS ((const char *));
 static struct hash_entry *init_test_hash_newfunc PARAMS ((struct hash_entry *,
                                                          struct hash_table *,
                                                          hash_table_key));
+static tree build_method_symbols_entry PARAMS ((tree));
+
 static rtx registerClass_libfunc;
 static rtx registerResource_libfunc;
 
@@ -1276,9 +1278,16 @@ make_method_value (mdecl)
 {
   static int method_name_count = 0;
   tree minit;
+  tree index;
   tree code;
 #define ACC_TRANSLATED          0x4000
   int accflags = get_access_flags_from_decl (mdecl) | ACC_TRANSLATED;
+
+  if (!flag_indirect_dispatch && DECL_VINDEX (mdecl) != NULL_TREE)
+    index = DECL_VINDEX (mdecl);
+  else
+    index = integer_minus_one_node;
+
   code = null_pointer_node;
   if (DECL_RTL_SET_P (mdecl))
     code = build1 (ADDR_EXPR, nativecode_ptr_type_node, mdecl);
@@ -1296,6 +1305,7 @@ make_method_value (mdecl)
                         IDENTIFIER_LENGTH(signature)))));
   }
   PUSH_FIELD_VALUE (minit, "accflags", build_int_2 (accflags, 0));
+  PUSH_FIELD_VALUE (minit, "index", index);
   PUSH_FIELD_VALUE (minit, "ncode", code);
 
   {
@@ -1541,7 +1551,7 @@ make_class_data (type)
   rest_of_decl_compilation (methods_decl, (char*) 0, 1, 0);
 
   if (assume_compiled (IDENTIFIER_POINTER (DECL_NAME (type_decl)))
-      && ! CLASS_INTERFACE (type_decl))
+      && ! CLASS_INTERFACE (type_decl) && !flag_indirect_dispatch)
     {
       tree dtable = get_dispatch_table (type, this_class_addr);
       dtable_decl = build_dtable_decl (type);
@@ -1635,7 +1645,12 @@ make_class_data (type)
   PUSH_FIELD_VALUE (cons, "methods",
                    build1 (ADDR_EXPR, method_ptr_type_node, methods_decl));
   PUSH_FIELD_VALUE (cons, "method_count",  build_int_2 (method_count, 0));
-  PUSH_FIELD_VALUE (cons, "vtable_method_count", TYPE_NVIRTUALS (type));
+
+  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));
+    
   PUSH_FIELD_VALUE (cons, "fields",
                    fields_decl == NULL_TREE ? null_pointer_node
                    : build1 (ADDR_EXPR, field_ptr_type_node, fields_decl));
@@ -1643,9 +1658,27 @@ make_class_data (type)
   PUSH_FIELD_VALUE (cons, "field_count", build_int_2 (field_count, 0));
   PUSH_FIELD_VALUE (cons, "static_field_count",
                    build_int_2 (static_field_count, 0));
-  PUSH_FIELD_VALUE (cons, "vtable",
-                   dtable_decl == NULL_TREE ? null_pointer_node
-                   : build1 (ADDR_EXPR, dtable_ptr_type, dtable_decl));
+
+  if (flag_indirect_dispatch)
+    PUSH_FIELD_VALUE (cons, "vtable", null_pointer_node)
+  else
+    PUSH_FIELD_VALUE (cons, "vtable",
+                     dtable_decl == NULL_TREE ? null_pointer_node
+                     : build1 (ADDR_EXPR, dtable_ptr_type, dtable_decl));
+  
+  if (otable_methods == NULL_TREE)
+    {
+      PUSH_FIELD_VALUE (cons, "otable", null_pointer_node);
+      PUSH_FIELD_VALUE (cons, "otable_syms", null_pointer_node);
+    }
+  else
+    {
+      PUSH_FIELD_VALUE (cons, "otable",
+                       build1 (ADDR_EXPR, otable_ptr_type, otable_decl));
+      PUSH_FIELD_VALUE (cons, "otable_syms",
+                       build1 (ADDR_EXPR, method_symbols_array_ptr_type,
+                               otable_syms_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));
@@ -2160,6 +2193,87 @@ emit_register_classes ()
     }
 }
 
+/* Make a method_symbol_type (_Jv_MethodSymbol) node for METHOD. */
+
+tree
+build_method_symbols_entry (tree method)
+{
+  tree clname, name, signature, method_symbol;
+  
+  clname = build_utf8_ref (DECL_NAME (TYPE_NAME (DECL_CONTEXT (method))));
+  name = build_utf8_ref (DECL_NAME (method));
+  signature = build_java_signature (TREE_TYPE (method));
+  signature = build_utf8_ref (unmangle_classname 
+                             (IDENTIFIER_POINTER (signature),
+                              IDENTIFIER_LENGTH (signature)));
+
+  START_RECORD_CONSTRUCTOR (method_symbol, method_symbol_type);
+  PUSH_FIELD_VALUE (method_symbol, "clname", clname);
+  PUSH_FIELD_VALUE (method_symbol, "name", name);
+  PUSH_FIELD_VALUE (method_symbol, "signature", signature);
+  FINISH_RECORD_CONSTRUCTOR (method_symbol);
+  TREE_CONSTANT (method_symbol) = 1;
+
+  return method_symbol;
+} 
+
+/* Emit the offset symbols table for indirect virtual dispatch. */
+
+void
+emit_offset_symbol_table ()
+{
+  tree method_list, method, table, list, null_symbol;
+  tree otable_bound, otable_array_type;
+  int index;
+  
+  /* Only emit an offset table if this translation unit actually made virtual 
+     calls. */
+  if (otable_methods == NULL_TREE)
+    return;
+
+  /* Build a list of _Jv_MethodSymbols for each entry in otable_methods. */
+  index = 0;
+  method_list = otable_methods;
+  list = NULL_TREE;  
+  while (method_list != NULL_TREE)
+    {
+      method = TREE_VALUE (method_list);
+      list = tree_cons (NULL_TREE, build_method_symbols_entry (method), list);
+      method_list = TREE_CHAIN (method_list);
+      index++;
+    }
+
+  /* Terminate the list with a "null" entry. */
+  START_RECORD_CONSTRUCTOR (null_symbol, method_symbol_type);
+  PUSH_FIELD_VALUE (null_symbol, "clname", null_pointer_node);
+  PUSH_FIELD_VALUE (null_symbol, "name", null_pointer_node);
+  PUSH_FIELD_VALUE (null_symbol, "signature", null_pointer_node);
+  FINISH_RECORD_CONSTRUCTOR (null_symbol);
+  TREE_CONSTANT (null_symbol) = 1;  
+  list = tree_cons (NULL_TREE, null_symbol, list);
+
+  /* Put the list in the right order and make it a constructor. */
+  list = nreverse (list);
+  table = build (CONSTRUCTOR, method_symbols_array_type, NULL_TREE, list);  
+
+  /* Make it the initial value for otable_syms and emit the decl. */
+  DECL_INITIAL (otable_syms_decl) = table;
+  DECL_ARTIFICIAL (otable_syms_decl) = 1;
+  DECL_IGNORED_P (otable_syms_decl) = 1;
+  rest_of_decl_compilation (otable_syms_decl, NULL, 1, 0);
+  
+  /* Now that its size is known, redefine otable as an uninitialized static 
+     array of INDEX + 1 integers. The extra entry is used by the runtime 
+     to track whether the otable has been initialized. */
+  otable_bound = build_index_type (build_int_2 (index, 0));
+  otable_array_type = build_array_type (integer_type_node, otable_bound);
+  otable_decl = build_decl (VAR_DECL, get_identifier ("otable"), 
+                           otable_array_type);
+  TREE_STATIC (otable_decl) = 1;
+  TREE_READONLY (otable_decl) = 1;  
+  rest_of_decl_compilation (otable_decl, NULL, 1, 0);
+}
+
 void
 init_class_processing ()
 {
index 17b3607a8717aef692257f19566c362c4ceea03a..4cfa9ba7ee0795d0dec2451ce686188c690fecd8 100644 (file)
@@ -614,6 +614,35 @@ java_init_decl_processing ()
   dtable_type = make_node (RECORD_TYPE);
   dtable_ptr_type = build_pointer_type (dtable_type);
 
+  otable_type = make_node (RECORD_TYPE);
+  otable_ptr_type = build_pointer_type (otable_type);
+
+  method_symbol_type = make_node (RECORD_TYPE);
+  PUSH_FIELD (method_symbol_type, field, "clname", utf8const_ptr_type);
+  PUSH_FIELD (method_symbol_type, field, "name", utf8const_ptr_type);
+  PUSH_FIELD (method_symbol_type, field, "signature", utf8const_ptr_type);
+  FINISH_RECORD (method_symbol_type);
+
+  one_elt_array_domain_type = build_index_type (integer_one_node);
+  method_symbols_array_type = build_array_type (method_symbol_type, 
+                                               one_elt_array_domain_type);
+  method_symbols_array_ptr_type = build_pointer_type 
+                                 (method_symbols_array_type);
+
+  otable_decl = build_decl (VAR_DECL, get_identifier ("otable"), 
+                           build_array_type (integer_type_node, 
+                           one_elt_array_domain_type));
+  DECL_EXTERNAL (otable_decl) = 1;
+  TREE_STATIC (otable_decl) = 1;
+  TREE_READONLY (otable_decl) = 1;
+  pushdecl (otable_decl);
+  
+  otable_syms_decl = build_decl (VAR_DECL, get_identifier ("otable_syms"), 
+    method_symbols_array_type);
+  TREE_STATIC (otable_syms_decl) = 1;
+  TREE_CONSTANT (otable_syms_decl) = 1;
+  pushdecl (otable_syms_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
@@ -647,6 +676,9 @@ java_init_decl_processing ()
   PUSH_FIELD (class_type_node, field, "field_count", short_type_node);
   PUSH_FIELD (class_type_node, field, "static_field_count", short_type_node);
   PUSH_FIELD (class_type_node, field, "vtable", dtable_ptr_type);
+  PUSH_FIELD (class_type_node, field, "otable", otable_ptr_type);
+  PUSH_FIELD (class_type_node, field, "otable_syms", 
+             method_symbols_array_ptr_type);
   PUSH_FIELD (class_type_node, field, "interfaces",
              build_pointer_type (class_ptr_type));
   PUSH_FIELD (class_type_node, field, "loader", ptr_type_node);
@@ -661,6 +693,7 @@ java_init_decl_processing ()
   for (t = TYPE_FIELDS (class_type_node);  t != NULL_TREE;  t = TREE_CHAIN (t))
     FIELD_PRIVATE (t) = 1;
   push_super_field (class_type_node, object_type_node);
+
   FINISH_RECORD (class_type_node);
   build_decl (TYPE_DECL, get_identifier ("Class"), class_type_node);
 
@@ -680,7 +713,6 @@ java_init_decl_processing ()
   FINISH_RECORD (field_type_node);
   build_decl (TYPE_DECL, get_identifier ("Field"), field_type_node);
 
-  one_elt_array_domain_type = build_index_type (integer_one_node);
   nativecode_ptr_array_type_node
     = build_array_type (nativecode_ptr_type_node, one_elt_array_domain_type);
 
@@ -717,6 +749,7 @@ java_init_decl_processing ()
   PUSH_FIELD (method_type_node, field, "name", utf8const_ptr_type);
   PUSH_FIELD (method_type_node, field, "signature", utf8const_ptr_type);
   PUSH_FIELD (method_type_node, field, "accflags", access_flags_type_node);
+  PUSH_FIELD (method_type_node, field, "index", unsigned_short_type_node);
   PUSH_FIELD (method_type_node, field, "ncode", nativecode_ptr_type_node);
   PUSH_FIELD (method_type_node, field, "throws", ptr_type_node);
   FINISH_RECORD (method_type_node);
index ef1a13959e1e156e80a5d715e7f016447dfb8e10..e5d141ea5e4273472a17766cefa4d8dcd9a90bc5 100644 (file)
@@ -84,6 +84,7 @@ static tree case_identity PARAMS ((tree, tree));
 static unsigned char peek_opcode_at_pc PARAMS ((struct JCF *, int, int));
 static bool emit_init_test_initialization PARAMS ((struct hash_entry *,
                                                   PTR ptr));
+static int get_offset_table_index PARAMS ((tree));
 
 static tree operand_type[59];
 extern struct obstack permanent_obstack;
@@ -1856,6 +1857,40 @@ invoke_build_dtable (is_invoke_interface, arg_list)
   return dtable;
 }
 
+/* Determine the index in the virtual offset table (otable) for a call to
+   METHOD. If this method has not been seen before, it will be added to the 
+   otable_methods. If it has, the existing otable slot will be reused. */
+
+int
+get_offset_table_index (method)
+     tree method;
+{
+  int i = 1;
+  tree method_list;
+  
+  if (otable_methods == NULL_TREE)
+    {
+      otable_methods = build_tree_list (method, method);
+      return 1;
+    }
+  
+  method_list = otable_methods;
+  
+  while (1)
+    {
+      if (TREE_VALUE (method_list) == method)
+        return i;
+      i++;
+      if (TREE_CHAIN (method_list) == NULL_TREE)
+        break;
+      else
+        method_list = TREE_CHAIN (method_list);
+    }
+
+  TREE_CHAIN (method_list) = build_tree_list (method, method);
+  return i;
+}
+
 tree 
 build_invokevirtual (dtable, method)
      tree dtable, method;
@@ -1863,20 +1898,33 @@ build_invokevirtual (dtable, method)
   tree func;
   tree nativecode_ptr_ptr_type_node
     = build_pointer_type (nativecode_ptr_type_node);
-  tree method_index = convert (sizetype, DECL_VINDEX (method));
+  tree method_index;
+  tree otable_index;
 
-  if (TARGET_VTABLE_USES_DESCRIPTORS)
-    /* Add one to skip bogus descriptor for class and GC descriptor. */
-    method_index = size_binop (PLUS_EXPR, method_index, size_int (1));
+  if (flag_indirect_dispatch)
+    {
+      otable_index = build_int_2 (get_offset_table_index (method), 0);
+      method_index = build (ARRAY_REF, integer_type_node, otable_decl, 
+                           otable_index);
+    }
   else
-    /* Add 1 to skip "class" field of dtable, and 1 to skip GC descriptor.  */
-    method_index = size_binop (PLUS_EXPR, method_index, size_int (2));
-  method_index = size_binop (MULT_EXPR, method_index,
-                            TYPE_SIZE_UNIT (nativecode_ptr_ptr_type_node));
+    {
+      method_index = convert (sizetype, DECL_VINDEX (method));
 
-  if (TARGET_VTABLE_USES_DESCRIPTORS)
-    method_index = size_binop (MULT_EXPR, method_index,
-                              size_int (TARGET_VTABLE_USES_DESCRIPTORS));
+      if (TARGET_VTABLE_USES_DESCRIPTORS)
+       /* Add one to skip bogus descriptor for class and GC descriptor. */
+       method_index = size_binop (PLUS_EXPR, method_index, size_int (1));
+      else
+       /* Add 1 to skip "class" field of dtable, and 1 to skip GC descriptor.  */
+       method_index = size_binop (PLUS_EXPR, method_index, size_int (2));
+
+      method_index = size_binop (MULT_EXPR, method_index,
+                                TYPE_SIZE_UNIT (nativecode_ptr_ptr_type_node));
+
+      if (TARGET_VTABLE_USES_DESCRIPTORS)
+       method_index = size_binop (MULT_EXPR, method_index,
+                                  size_int (TARGET_VTABLE_USES_DESCRIPTORS));
+    }
 
   func = fold (build (PLUS_EXPR, nativecode_ptr_ptr_type_node, dtable,
                      convert (nativecode_ptr_ptr_type_node, method_index)));
@@ -1898,6 +1946,7 @@ build_invokeinterface (dtable, method)
   tree interface;
   tree idx;
   tree meth;
+  tree otable_index;
   int i;
 
   /* We expand invokeinterface here.  _Jv_LookupInterfaceMethod() will
@@ -1917,16 +1966,24 @@ build_invokeinterface (dtable, method)
   interface = DECL_CONTEXT (method);
   layout_class_methods (interface);
   
-  i = 1;
-  for (meth = TYPE_METHODS (interface); ; meth = TREE_CHAIN (meth), i++)
+  if (flag_indirect_dispatch)
     {
-      if (meth == method)
-        {
-         idx = build_int_2 (i, 0);
-         break;
+      otable_index = build_int_2 (get_offset_table_index (method), 0);
+      idx = build (ARRAY_REF, integer_type_node, otable_decl, otable_index);
+    }
+  else
+    {
+      i = 1;
+      for (meth = TYPE_METHODS (interface); ; meth = TREE_CHAIN (meth), i++)
+       {
+         if (meth == method)
+            {
+             idx = build_int_2 (i, 0);
+             break;
+           }
+         if (meth == NULL_TREE)
+           abort ();
        }
-      if (meth == NULL_TREE)
-       abort ();
     }
 
   lookup_arg = tree_cons (NULL_TREE, dtable,
index 9d11bf6baf12b63a8f3dd655e08a8626582463d4..17a06382815dfc4b3d283d0d30b3161d19687d3d 100644 (file)
@@ -141,6 +141,18 @@ extern int compiling_from_source;
 /* List of all class filenames seen so far.  */
 #define all_class_filename java_global_trees [JTI_ALL_CLASS_FILENAME]
 
+/* List of virtual method decls called in this translation unit, used to 
+   generate virtual method offset symbol table. */
+#define otable_methods java_global_trees [JTI_OTABLE_METHODS]
+
+/* The virtual method offset table. This is emitted as uninitialized data of 
+   the required length, and filled out at run time during class linking. */
+#define otable_decl java_global_trees [JTI_OTABLE_DECL]
+
+/* The virtual method offset symbol table. Used by the runtime to fill out the
+   otable. */
+#define otable_syms_decl java_global_trees [JTI_OTABLE_SYMS_DECL]
+
 extern int flag_emit_class_files;
 
 extern int flag_filelist_file;
@@ -196,6 +208,10 @@ extern int flag_check_references;
    initialization optimization should be performed.  */
 extern int flag_optimize_sci;
 
+/* When non zero, use offset tables for virtual method calls
+   in order to improve binary compatibility. */
+extern int flag_indirect_dispatch;
+
 /* Encoding used for source files.  */
 extern const char *current_encoding;
 
@@ -331,6 +347,11 @@ enum java_tree_index
   JTI_LINENUMBERS_TYPE,
   JTI_METHOD_TYPE_NODE,
   JTI_METHOD_PTR_TYPE_NODE,
+  JTI_OTABLE_TYPE,
+  JTI_OTABLE_PTR_TYPE,
+  JTI_METHOD_SYMBOL_TYPE,
+  JTI_METHOD_SYMBOLS_ARRAY_TYPE,
+  JTI_METHOD_SYMBOLS_ARRAY_PTR_TYPE,
 
   JTI_END_PARAMS_NODE,
 
@@ -370,6 +391,10 @@ enum java_tree_index
   JTI_ALL_CLASS_LIST,
   JTI_ALL_CLASS_FILENAME,
 
+  JTI_OTABLE_METHODS,
+  JTI_OTABLE_DECL,
+  JTI_OTABLE_SYMS_DECL,
+
   JTI_MAX
 };
 
@@ -565,6 +590,16 @@ extern tree java_global_trees[JTI_MAX];
   java_global_trees[JTI_METHOD_TYPE_NODE]
 #define method_ptr_type_node \
   java_global_trees[JTI_METHOD_PTR_TYPE_NODE]
+#define otable_type \
+  java_global_trees[JTI_OTABLE_TYPE]
+#define otable_ptr_type \
+  java_global_trees[JTI_OTABLE_PTR_TYPE]
+#define method_symbol_type \
+  java_global_trees[JTI_METHOD_SYMBOL_TYPE]
+#define method_symbols_array_type \
+  java_global_trees[JTI_METHOD_SYMBOLS_ARRAY_TYPE]
+#define method_symbols_array_ptr_type \
+  java_global_trees[JTI_METHOD_SYMBOLS_ARRAY_PTR_TYPE]
 
 #define end_params_node \
   java_global_trees[JTI_END_PARAMS_NODE]
@@ -1098,6 +1133,7 @@ extern void make_class_data PARAMS ((tree));
 extern void register_class PARAMS ((void));
 extern int alloc_name_constant PARAMS ((int, tree));
 extern void emit_register_classes PARAMS ((void));
+extern void emit_offset_symbol_table PARAMS ((void));
 extern void lang_init_source PARAMS ((int));
 extern void write_classfile PARAMS ((tree));
 extern char *print_int_node PARAMS ((tree));
index 15dcd071e5fb9ea8f84fa0a6d15587ef33c75fc4..61d097297274907597cb17df3409c83aeccd11e8 100644 (file)
@@ -1188,7 +1188,11 @@ yyparse ()
 
   java_expand_classes ();
   if (!java_report_errors () && !flag_syntax_only)
-    emit_register_classes ();
+    {
+      emit_register_classes ();
+      if (flag_indirect_dispatch)
+       emit_offset_symbol_table ();
+    }
   return 0;
 }
 
index 1b53bf5a7a0f37dfe420adb2c798e2461e922f60..1fd4f4cc87a089785776e934766f55865241c2f9 100644 (file)
@@ -64,6 +64,7 @@ const char jvgenmain_spec[] =
                    %{<fcompile-resource*}\
                   %{<femit-class-file} %{<femit-class-files} %{<fencoding*}\
                   %{<fuse-boehm-gc} %{<fhash-synchronization} %{<fjni}\
+                  %{<findirect-dispatch} \
                   %{<fclasspath*} %{<fCLASSPATH*} %{<foutput-class-dir}\
                   %{<fuse-divide-subroutine} %{<fno-use-divide-subroutine}\
                   %{<fcheck-references} %{<fno-check-references}\
index c07c5868017b13e66cb310943f872db032d386b8..11e036ca38a7603b1f748b9de1aed148d0685a66 100644 (file)
@@ -153,6 +153,10 @@ int flag_force_classes_archive_check;
    be tested alone, use STATIC_CLASS_INITIALIZATION_OPTIMIZATION_P instead.  */
 int flag_optimize_sci = 1;
 
+/* When non zero, use offset tables for virtual method calls
+   in order to improve binary compatibility. */
+int flag_indirect_dispatch = 0;
+
 /* When non zero, print extra version information.  */
 static int version_flag = 0;
 
@@ -174,7 +178,8 @@ lang_f_options[] =
   {"jni", &flag_jni, 1},
   {"check-references", &flag_check_references, 1},
   {"force-classes-archive-check", &flag_force_classes_archive_check, 1},
-  {"optimize-static-class-initialization", &flag_optimize_sci, 1 }
+  {"optimize-static-class-initialization", &flag_optimize_sci, 1 },
+  {"indirect-dispatch", &flag_indirect_dispatch, 1}
 };
 
 static struct string_option
index 3a3294cc366ab9bc367eee7c12d1a4e11d4f91e7..39375cf8612ea82ade4e023b3bd69e566df74820 100644 (file)
@@ -1,3 +1,19 @@
+2001-12-15  Bryce McKinlay  <bryce@waitaki.otago.ac.nz>
+
+       * include/jvm.h (_Jv_VTable::idx_to_offset): New method.
+       * java/lang/natClassLoader.cc (_Jv_PrepareCompiledClass): Call
+       _Jv_MakeVTable and _Jv_LinkOffsetTable if needed.
+       * java/lang/Class.h (_Jv_Method): Add "index" field.
+       (_Jv_MethodSymbol): New struct type.
+       (_Jv_LinkOffsetTable, _Jv_LayoutVTableMethods, _Jv_SetVTableEntries,
+       _Jv_MakeVTable): Friends.
+       (otable, otable_syms): New Class fields.
+       * java/lang/natClass.cc (_Jv_LinkOffsetTable): New function.
+       (isVirtualMethod): New static function.
+       (_Jv_LayoutVTableMethods): New function.
+       (_Jv_SetVTableEntries): New function.
+       (_Jv_MakeVTable): New function.
+
 2001-12-15  Bryce McKinlay  <bryce@waitaki.otago.ac.nz>
 
        * java/util/BitSet.java (and): Fix off-by-one bug, don't skip part of
index 57ba44fbfadac1924f9641639c833c8ccddb9065..ada8e11a2e1bced0f40696cb6246a29af7c9cd3b 100644 (file)
@@ -57,6 +57,12 @@ struct _Jv_VTable
 #endif
 
   static size_t vtable_elt_size() { return sizeof(vtable_elt); }
+
+  // Given a method index, return byte offset from the vtable pointer.
+  static jint idx_to_offset (int index)
+  {
+    return (2 * sizeof (void *)) + (index * vtable_elt_size ());
+  }
   static _Jv_VTable *new_vtable (int count);
 };
 
index aac5f12dd26ef322a45137ad9dc7d571905cecbf..20523912e583554b5b27cbbd33e4f43711a86d56 100644 (file)
@@ -70,6 +70,8 @@ struct _Jv_Method
   _Jv_Utf8Const *signature;
   // Access flags.
   _Jv_ushort accflags;
+  // Method's index in the vtable.
+  _Jv_ushort index;
   // Pointer to underlying function.
   void *ncode;
   // NULL-terminated list of exception class names; can be NULL if
@@ -114,6 +116,19 @@ union _Jv_Self
   jclass self;
 };
 
+struct _Jv_MethodSymbol
+{
+  _Jv_Utf8Const *class_name;
+  _Jv_Utf8Const *name;
+  _Jv_Utf8Const *signature;
+};
+
+struct _Jv_OffsetTable
+{
+  jint state;
+  jint offsets[];
+};
+
 #define JV_PRIMITIVE_VTABLE ((_Jv_VTable *) -1)
 
 #define JV_CLASS(Obj) ((jclass) (*(_Jv_VTable **) Obj)->clas)
@@ -303,6 +318,10 @@ private:
   friend jstring _Jv_GetMethodString(jclass, _Jv_Utf8Const *);
   friend jshort _Jv_AppendPartialITable (jclass, jclass, void **, jshort);
   friend jshort _Jv_FindIIndex (jclass *, jshort *, jshort);
+  friend void _Jv_LinkOffsetTable (jclass);
+  friend void _Jv_LayoutVTableMethods (jclass klass);
+  friend void _Jv_SetVTableEntries (jclass, _Jv_VTable *);
+  friend void _Jv_MakeVTable (jclass);
 
   // Return array class corresponding to element type KLASS, creating it if
   // necessary.
@@ -367,6 +386,10 @@ private:
   jshort static_field_count;
   // The vtbl for all objects of this class.
   _Jv_VTable *vtable;
+  // Virtual method offset table.
+  _Jv_OffsetTable *otable;
+  // Offset table symbols.
+  _Jv_MethodSymbol *otable_syms;
   // Interfaces implemented by this class.
   jclass *interfaces;
   // The class loader for this class.
index 54289b34102a00a7df53576a5b4415747ea367d5..6dfe14bab717360140cb69b44dbb0eb8d75a3a4d 100644 (file)
@@ -692,7 +692,7 @@ java::lang::Class::initializeClass (void)
          _Jv_PrepareCompiledClass (this);
        }
     }
-  
+
   if (state <= JV_STATE_LINKED)
     _Jv_PrepareConstantTimeTables (this);
 
@@ -1422,3 +1422,194 @@ java::lang::Class::getProtectionDomain0 ()
 {
   return protectionDomain;
 }
+
+// Functions for indirect dispatch (symbolic virtual method binding) support.
+
+// Resolve entries in the virtual method offset symbol table 
+// (klass->otable_syms). The vtable offset (in bytes) for each resolved method 
+// is placed at the corresponding position in the virtual method offset table 
+// (klass->otable). A single otable and otable_syms pair may be shared by many 
+// classes.
+void
+_Jv_LinkOffsetTable(jclass klass)
+{
+  //// FIXME: Need to lock the otable ////
+  
+  if (klass->otable == NULL
+      || klass->otable->state != 0)
+    return;
+  
+  klass->otable->state = 1;
+
+  int index = 0;
+  _Jv_MethodSymbol sym = klass->otable_syms[0];
+
+  while (sym.name != NULL)
+    {
+      jclass target_class = _Jv_FindClass (sym.class_name, NULL);
+      _Jv_Method *meth = NULL;            
+      
+      if (target_class != NULL)
+       if (target_class->isInterface())
+         {
+           // FIXME: This does not yet fully conform to binary compatibility
+           // rules. It will break if a declaration is moved into a 
+           // superinterface.
+           for (int i=0; i < target_class->method_count; i++)
+             {
+               meth = &target_class->methods[i];
+               if (_Jv_equalUtf8Consts (sym.name, meth->name)
+                   && _Jv_equalUtf8Consts (sym.signature, meth->signature))
+                 {
+                   klass->otable->offsets[index] = i + 1;
+                   break;
+                 }
+             }
+         }
+       else
+         {
+           // If the target class does not have a vtable_method_count yet, 
+           // then we can't tell the offsets for its methods, so we must lay 
+           // it out now.
+           if (target_class->vtable_method_count == -1)
+             {
+               JvSynchronize sync (target_class);
+               _Jv_LayoutVTableMethods (target_class);
+             }
+
+            meth = _Jv_LookupDeclaredMethod(target_class, sym.name, 
+                                           sym.signature);
+
+           if (meth != NULL)
+             {
+               klass->otable->offsets[index] = 
+                 _Jv_VTable::idx_to_offset (meth->index);
+             }
+         }
+
+      if (meth == NULL)
+       // FIXME: This should be special index for ThrowNoSuchMethod().
+       klass->otable->offsets[index] = -1;
+
+      sym = klass->otable_syms[++index];
+    }
+}
+
+// Returns true if METH should get an entry in a VTable.
+static bool
+isVirtualMethod (_Jv_Method *meth)
+{
+  using namespace java::lang::reflect;
+  return (((meth->accflags & (Modifier::STATIC | Modifier::PRIVATE)) == 0)
+          && meth->name->data[0] != '<');
+}
+
+// Prepare virtual method declarations in KLASS, and any superclasses as 
+// required, by determining their vtable index, setting method->index, and
+// finally setting the class's vtable_method_count. Must be called with the
+// lock for KLASS held.
+void
+_Jv_LayoutVTableMethods (jclass klass)
+{
+  if (klass->vtable != NULL || klass->isInterface() 
+      || klass->vtable_method_count != -1)
+    return;
+    
+  jclass superclass = klass->superclass;
+
+  if (superclass != NULL && superclass->vtable_method_count == -1)
+    {
+      JvSynchronize sync (superclass);
+      _Jv_LayoutVTableMethods (superclass);
+    }
+    
+  int index = (superclass == NULL ? 0 : superclass->vtable_method_count);
+
+  for (int i = 0; i < klass->method_count; ++i)
+    {
+      _Jv_Method *meth = &klass->methods[i];
+      _Jv_Method *super_meth = NULL;
+    
+      if (!isVirtualMethod(meth))
+        continue;
+             
+      if (superclass != NULL)
+        super_meth = _Jv_LookupDeclaredMethod (superclass, meth->name, 
+                                              meth->signature);
+      
+      if (super_meth)
+        meth->index = super_meth->index;
+      else
+        meth->index = index++;
+    }
+  
+  klass->vtable_method_count = index;
+}
+
+// Set entries in VTABLE for virtual methods declared in KLASS. If KLASS has
+// an immediate abstract parent, recursivly do its methods first.
+void
+_Jv_SetVTableEntries (jclass klass, _Jv_VTable *vtable)
+{
+  using namespace java::lang::reflect;
+
+  jclass superclass = klass->getSuperclass();
+
+  if (superclass != NULL && (superclass->getModifiers() & Modifier::ABSTRACT))
+    _Jv_SetVTableEntries (superclass, vtable);
+    
+  for (int i = klass->method_count - 1; i >= 0; i--)
+    {
+      _Jv_Method *meth = &klass->methods[i];
+      if (!isVirtualMethod(meth))
+       continue;
+      vtable->set_method(meth->index, meth->ncode);
+    }
+}
+
+// Allocate and lay out the virtual method table for KLASS. This will also
+// cause vtables to be generated for any non-abstract superclasses, and
+// virtual method layout to occur for any abstract superclasses. Must be
+// called with monitor lock for KLASS held.
+void
+_Jv_MakeVTable (jclass klass)
+{
+  using namespace java::lang::reflect;  
+
+  if (klass->vtable != NULL || klass->isInterface() 
+      || (klass->accflags & Modifier::ABSTRACT))
+    return;
+  
+  //  out before we can create a vtable. 
+  if (klass->vtable_method_count == -1)
+    _Jv_LayoutVTableMethods (klass);
+
+  // Allocate the new vtable.
+  _Jv_VTable *vtable = _Jv_VTable::new_vtable (klass->vtable_method_count);
+  klass->vtable = vtable;
+  
+  // Copy the vtable of the closest non-abstract superclass.
+  jclass superclass = klass->superclass;
+  if (superclass != NULL)
+    {
+      while ((superclass->accflags & Modifier::ABSTRACT) != 0)
+       superclass = superclass->superclass;
+
+      if (superclass->vtable == NULL)
+       {
+         JvSynchronize sync (superclass);
+         _Jv_MakeVTable (superclass);
+       }
+
+      for (int i = 0; i < superclass->vtable_method_count; ++i)
+       vtable->set_method (i, superclass->vtable->get_method (i));
+    }
+
+  // Set the class pointer and GC descriptor.
+  vtable->clas = klass;
+  vtable->gc_descr = _Jv_BuildGCDescr (klass);
+
+  // For each virtual declared in klass and any immediate abstract 
+  // superclasses, set new vtable entry or override an old one.
+  _Jv_SetVTableEntries (klass, vtable);
+}
index 59aca071ea2cc8b62312b91c721e06151137fb97..ffe5b18fbe04f10689b8957ce063a0b2259f7126 100644 (file)
@@ -234,7 +234,6 @@ java::lang::ClassLoader::findLoadedClass (jstring name)
   return _Jv_FindClassInCache (_Jv_makeUtf8Const (name), this);
 }
 
-
 /** This function does class-preparation for compiled classes.  
     NOTE: It contains replicated functionality from
     _Jv_ResolvePoolEntry, and this is intentional, since that function
@@ -309,6 +308,12 @@ _Jv_PrepareCompiledClass (jclass klass)
     }
 #endif /* INTERPRETER */
 
+  if (klass->vtable == NULL)
+    _Jv_MakeVTable(klass);
+
+  if (klass->otable != NULL && klass->otable->state == 0)
+    _Jv_LinkOffsetTable(klass);
+
   klass->notifyAll ();
 }