Java: binary compatibility

Andrew Haley aph@redhat.com
Thu Sep 25 18:21:00 GMT 2003


This is still a work in progress, but as it meets all the binary
compatibility tests it's something of a milestone.

The final form of the ABI is still undecided.  We need to think about
about what might be the right symbol table format.  This patch uses
two tables, one of addresses and one of offsets, called atable and
otable respectively.  It's fairly efficient, but optimization work is
needed.

There's still a few direct references, such as the superclass pointer.
I'm going to keep working on this with a view to making it more
efficient and more general.

Andrew.



2003-09-25  Andrew Haley  <aph@redhat.com>

	* jcf-parse.c (java_parse_file): Write otable and atable.
	* java-tree.h (atable_methods): New.
	(atable_decl): New.
	(atable_syms_decl): New.
	(enum java_tree_index): Add JTI_ATABLE_METHODS, JTI_ATABLE_DECL,
	JTI_ATABLE_SYMS_DECL.  Rename JTI_METHOD_SYMBOL* to JTI_SYMBOL*.
	(symbol_*type): Rename method_symbol* to symbol*type.	
	(emit_offset_symbol_table): Delete.
	(emit_symbol_table): New.
	(get_symbol_table_index): New.
	(atable_type): New.
	* expr.c (build_field_ref): Handle flag_indirect_dispatch.
	(build_known_method_ref): Likewise.
	(get_symbol_table_index): Rename from get_offset_table_index.
	Parameterize to allow re-use by differing types of symbol table.
	(build_invokevirtual): Pass table to get_offset_table_index.
	* decl.c (java_init_decl_processing): Push types and decls for
	atable and atable_syyms.
	* class.c (build_static_field_ref): Handle flag_indirect_dispatch.
	(make_class_data): Add new fields atable and atable_syms.
	(emit_symbol_table): Rename from emit_offset_symbol_table.
	Parameterize to allow re-use by different types of symbol table.
	(build_symbol_entry): Renamed from build_method_symbols_entry.
	
Index: gcc/java/class.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/java/class.c,v
retrieving revision 1.169
diff -c -2 -p -r1.169 class.c
*** gcc/java/class.c	24 Sep 2003 13:07:25 -0000	1.169
--- gcc/java/class.c	25 Sep 2003 17:59:06 -0000
*************** static tree maybe_layout_super_class (tr
*** 60,64 ****
  static void add_miranda_methods (tree, tree);
  static int assume_compiled (const char *);
! static tree build_method_symbols_entry (tree);
  
  static GTY(()) rtx registerClass_libfunc;
--- 60,64 ----
  static void add_miranda_methods (tree, tree);
  static int assume_compiled (const char *);
! static tree build_symbol_entry (tree);
  
  static GTY(()) rtx registerClass_libfunc;
*************** build_static_field_ref (tree fdecl)
*** 926,930 ****
       returning the field itself, leading to an incorrect external
       reference being generated.  */
!   if (is_compiled
        || (FIELD_FINAL (fdecl) && DECL_INITIAL (fdecl) != NULL_TREE
  	  && (JSTRING_TYPE_P (TREE_TYPE (fdecl))
--- 926,931 ----
       returning the field itself, leading to an incorrect external
       reference being generated.  */
!   if ((is_compiled 
!        && (! flag_indirect_dispatch || current_class == fclass))
        || (FIELD_FINAL (fdecl) && DECL_INITIAL (fdecl) != NULL_TREE
  	  && (JSTRING_TYPE_P (TREE_TYPE (fdecl))
*************** build_static_field_ref (tree fdecl)
*** 940,944 ****
        return fdecl;
      }
!   else
      {
        /* Compile as:
--- 941,956 ----
        return fdecl;
      }
! 
!   if (flag_indirect_dispatch)
!     {
!       tree table_index 
! 	= build_int_2 (get_symbol_table_index (fdecl, &atable_methods), 0);
!       tree field_address
! 	= build (ARRAY_REF, build_pointer_type (TREE_TYPE (fdecl)), 
! 		 atable_decl, table_index);
!       return fold (build1 (INDIRECT_REF, TREE_TYPE (fdecl), 
! 			   field_address));
!     }
!   else  
      {
        /* Compile as:
*************** make_class_data (tree type)
*** 1501,1505 ****
  			       build1 (ADDR_EXPR, dtable_ptr_type, dtable_decl),
  			       dtable_start_offset));
-   
    if (otable_methods == NULL_TREE)
      {
--- 1513,1516 ----
*************** make_class_data (tree type)
*** 1512,1517 ****
  			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);
--- 1523,1543 ----
  			build1 (ADDR_EXPR, otable_ptr_type, otable_decl));
        PUSH_FIELD_VALUE (cons, "otable_syms",
! 			build1 (ADDR_EXPR, symbols_array_ptr_type,
  				otable_syms_decl));
+       TREE_CONSTANT (otable_decl) = 1;
+     }
+   if (atable_methods == NULL_TREE)
+     {
+       PUSH_FIELD_VALUE (cons, "atable", null_pointer_node);
+       PUSH_FIELD_VALUE (cons, "atable_syms", null_pointer_node);
+     }
+   else
+     {
+       PUSH_FIELD_VALUE (cons, "atable",
+ 			build1 (ADDR_EXPR, atable_ptr_type, atable_decl));
+       PUSH_FIELD_VALUE (cons, "atable_syms",
+ 			build1 (ADDR_EXPR, symbols_array_ptr_type,
+ 				atable_syms_decl));
+       TREE_CONSTANT (atable_decl) = 1;
      }
    PUSH_FIELD_VALUE (cons, "interfaces", interfaces);
*************** emit_register_classes (void)
*** 2099,2148 ****
  }
  
! /* Make a method_symbol_type (_Jv_MethodSymbol) node for METHOD. */
  
  static 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 (void)
  {
    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++;
--- 2125,2175 ----
  }
  
! /* Make a symbol_type (_Jv_MethodSymbol) node for DECL. */
  
  static tree
! build_symbol_entry (tree decl)
  {
!   tree clname, name, signature, sym;
    
!   clname = build_utf8_ref (DECL_NAME (TYPE_NAME (DECL_CONTEXT (decl))));
!   name = build_utf8_ref (DECL_NAME (decl));
!   signature = build_java_signature (TREE_TYPE (decl));
    signature = build_utf8_ref (unmangle_classname 
  			      (IDENTIFIER_POINTER (signature),
  			       IDENTIFIER_LENGTH (signature)));
  
!   START_RECORD_CONSTRUCTOR (sym, symbol_type);
!   PUSH_FIELD_VALUE (sym, "clname", clname);
!   PUSH_FIELD_VALUE (sym, "name", name);
!   PUSH_FIELD_VALUE (sym, "signature", signature);
!   FINISH_RECORD_CONSTRUCTOR (sym);
!   TREE_CONSTANT (sym) = 1;
  
!   return sym;
  } 
  
! /* Emit a symbol table: used by -findirect-dispatch.  */
  
! tree
! emit_symbol_table (tree name, tree the_table, tree decl_list, tree the_syms_decl, 
! 			  tree the_array_element_type)
  {
    tree method_list, method, table, list, null_symbol;
!   tree table_size, the_array_type;
    int index;
    
!   /* Only emit a table if this translation unit actually made any
!      references via it. */
!   if (decl_list == NULL_TREE)
!     return the_table;
  
    /* Build a list of _Jv_MethodSymbols for each entry in otable_methods. */
    index = 0;
!   method_list = decl_list;
    list = NULL_TREE;  
    while (method_list != NULL_TREE)
      {
        method = TREE_VALUE (method_list);
!       list = tree_cons (NULL_TREE, build_symbol_entry (method), list);
        method_list = TREE_CHAIN (method_list);
        index++;
*************** emit_offset_symbol_table (void)
*** 2150,2154 ****
  
    /* 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);
--- 2177,2181 ----
  
    /* Terminate the list with a "null" entry. */
!   START_RECORD_CONSTRUCTOR (null_symbol, symbol_type);
    PUSH_FIELD_VALUE (null_symbol, "clname", null_pointer_node);
    PUSH_FIELD_VALUE (null_symbol, "name", null_pointer_node);
*************** emit_offset_symbol_table (void)
*** 2160,2181 ****
    /* Put the list in the right order and make it a constructor. */
    list = nreverse (list);
!   table = build_constructor (method_symbols_array_type, 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);
  }
  
--- 2187,2210 ----
    /* Put the list in the right order and make it a constructor. */
    list = nreverse (list);
!   table = build_constructor (symbols_array_type, list);  
  
    /* Make it the initial value for otable_syms and emit the decl. */
!   DECL_INITIAL (the_syms_decl) = table;
!   DECL_ARTIFICIAL (the_syms_decl) = 1;
!   DECL_IGNORED_P (the_syms_decl) = 1;
!   rest_of_decl_compilation (the_syms_decl, NULL, 1, 0);
    
!   /* Now that its size is known, redefine the table as an
!      uninitialized static array of INDEX + 1 integers. The extra entry
!      is used by the runtime to track whether the table has been
!      initialized. */
!   table_size = build_index_type (build_int_2 (index, 0));
!   the_array_type = build_array_type (the_array_element_type, table_size);
!   the_table = build_decl (VAR_DECL, name, the_array_type);
!   TREE_STATIC (the_table) = 1;
!   TREE_READONLY (the_table) = 1;  
!   rest_of_decl_compilation (the_table, NULL, 1, 0);
! 
!   return the_table;
  }
  
Index: gcc/java/decl.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/java/decl.c,v
retrieving revision 1.164
diff -c -2 -p -r1.164 decl.c
*** gcc/java/decl.c	23 Sep 2003 03:05:30 -0000	1.164
--- gcc/java/decl.c	25 Sep 2003 17:59:06 -0000
*************** java_init_decl_processing (void)
*** 623,652 ****
    TYPE_NONALIASED_COMPONENT (otable_type) = 1;
    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);
! 
!   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);
  
    if (flag_indirect_dispatch)
      {
!       otable_decl = build_decl (VAR_DECL, get_identifier ("otable"),
! 				otable_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);
      }
    
--- 623,666 ----
    TYPE_NONALIASED_COMPONENT (otable_type) = 1;
    otable_ptr_type = build_pointer_type (otable_type);
!   atable_type = build_array_type (ptr_type_node, 
! 				  one_elt_array_domain_type);
!   TYPE_NONALIASED_COMPONENT (atable_type) = 1;
!   atable_ptr_type = build_pointer_type (atable_type);
! 
!   symbol_type = make_node (RECORD_TYPE);
!   PUSH_FIELD (symbol_type, field, "clname", utf8const_ptr_type);
!   PUSH_FIELD (symbol_type, field, "name", utf8const_ptr_type);
!   PUSH_FIELD (symbol_type, field, "signature", utf8const_ptr_type);
!   FINISH_RECORD (symbol_type);
! 
!   symbols_array_type = build_array_type (symbol_type, 
! 					 one_elt_array_domain_type);
!   symbols_array_ptr_type = build_pointer_type (symbols_array_type);
  
    if (flag_indirect_dispatch)
      {
!       otable_decl = build_decl (VAR_DECL, get_identifier ("otable"), otable_type);
        DECL_EXTERNAL (otable_decl) = 1;
        TREE_STATIC (otable_decl) = 1;
        TREE_READONLY (otable_decl) = 1;
!       TREE_CONSTANT (otable_decl) = 1;
!       pushdecl (otable_decl);  
        otable_syms_decl = build_decl (VAR_DECL, get_identifier ("otable_syms"), 
! 				     symbols_array_type);
        TREE_STATIC (otable_syms_decl) = 1;
        TREE_CONSTANT (otable_syms_decl) = 1;
        pushdecl (otable_syms_decl);
+ 
+       atable_decl = build_decl (VAR_DECL, get_identifier ("atable"), atable_type);
+       DECL_EXTERNAL (atable_decl) = 1;
+       TREE_STATIC (atable_decl) = 1;
+       TREE_READONLY (atable_decl) = 1;
+       TREE_CONSTANT (atable_decl) = 1;
+       pushdecl (atable_decl);  
+       atable_syms_decl = build_decl (VAR_DECL, get_identifier ("atable_syms"), 
+ 				     symbols_array_type);
+       TREE_STATIC (atable_syms_decl) = 1;
+       TREE_CONSTANT (atable_syms_decl) = 1;
+       pushdecl (atable_syms_decl);
      }
    
*************** java_init_decl_processing (void)
*** 686,690 ****
    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));
--- 700,707 ----
    PUSH_FIELD (class_type_node, field, "otable", otable_ptr_type);
    PUSH_FIELD (class_type_node, field, "otable_syms", 
!   	      symbols_array_ptr_type);
!   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, "interfaces",
  	      build_pointer_type (class_ptr_type));
Index: gcc/java/expr.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/java/expr.c,v
retrieving revision 1.172
diff -c -2 -p -r1.172 expr.c
*** gcc/java/expr.c	21 Sep 2003 05:07:19 -0000	1.172
--- gcc/java/expr.c	25 Sep 2003 17:59:07 -0000
*************** static tree case_identity (tree, tree); 
*** 85,89 ****
  static unsigned char peek_opcode_at_pc (struct JCF *, int, int);
  static int emit_init_test_initialization (void **entry, void * ptr);
- static int get_offset_table_index (tree);
  
  static GTY(()) tree operand_type[59];
--- 85,88 ----
*************** build_field_ref (tree self_value, tree s
*** 1513,1516 ****
--- 1512,1534 ----
        if (base_type != TREE_TYPE (self_value))
  	self_value = fold (build1 (NOP_EXPR, base_type, self_value));
+       if (flag_indirect_dispatch
+ 	  && current_class != self_class)
+ 	/* FIXME: current_class != self_class is not exactly the right
+ 	   test.  What we really want to know is whether self_class is
+ 	   in the same translation unit as current_class.  If it is,
+ 	   we can make a direct reference.  */
+ 	{
+ 	  tree otable_index 
+ 	    = build_int_2 
+ 	    (get_symbol_table_index (field_decl, &otable_methods), 0);
+ 	  tree field_offset = build (ARRAY_REF, integer_type_node, otable_decl, 
+ 				     otable_index);
+ 	  tree address 
+ 	    = fold (build (PLUS_EXPR, 
+ 			   build_pointer_type (TREE_TYPE (field_decl)),
+ 			   self_value, field_offset));
+ 	  return fold (build1 (INDIRECT_REF, TREE_TYPE (field_decl), address));
+ 	}
+ 
        self_value = build_java_indirect_ref (TREE_TYPE (TREE_TYPE (self_value)),
  					    self_value, check);
*************** build_known_method_ref (tree method, tre
*** 1747,1752 ****
    if (is_compiled_class (self_type))
      {
!       make_decl_rtl (method, NULL);
!       func = build1 (ADDR_EXPR, method_ptr_type_node, method);
      }
    else
--- 1765,1781 ----
    if (is_compiled_class (self_type))
      {
!       if (!flag_indirect_dispatch
! 	  || (!TREE_PUBLIC (method) && DECL_CONTEXT (method)))
! 	{
! 	  make_decl_rtl (method, NULL);
! 	  func = build1 (ADDR_EXPR, method_ptr_type_node, method);
! 	}
!       else
! 	{
! 	  tree table_index = build_int_2 (get_symbol_table_index 
! 					  (method, &atable_methods), 0);
! 	  func = build (ARRAY_REF,  method_ptr_type_node, atable_decl, 
! 			table_index);
! 	}
      }
    else
*************** invoke_build_dtable (int is_invoke_inter
*** 1823,1843 ****
     otable_methods. If it has, the existing otable slot will be reused. */
  
! static int
! get_offset_table_index (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++;
--- 1852,1873 ----
     otable_methods. If it has, the existing otable slot will be reused. */
  
! int
! get_symbol_table_index (tree t, tree *symbol_table)
  {
    int i = 1;
    tree method_list;
! 
!   if (*symbol_table == NULL_TREE)
      {
!       *symbol_table = build_tree_list (t, t);
        return 1;
      }
    
!   method_list = *symbol_table;
    
    while (1)
      {
!       tree value = TREE_VALUE (method_list);
!       if (value == t)
          return i;
        i++;
*************** get_offset_table_index (tree method)
*** 1848,1852 ****
      }
  
!   TREE_CHAIN (method_list) = build_tree_list (method, method);
    return i;
  }
--- 1878,1882 ----
      }
  
!   TREE_CHAIN (method_list) = build_tree_list (t, t);
    return i;
  }
*************** build_invokevirtual (tree dtable, tree m
*** 1863,1867 ****
    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);
--- 1893,1898 ----
    if (flag_indirect_dispatch)
      {
!       otable_index 
! 	= build_int_2 (get_symbol_table_index (method, &otable_methods), 0);
        method_index = build (ARRAY_REF, integer_type_node, otable_decl, 
  			    otable_index);
*************** build_invokeinterface (tree dtable, tree
*** 1927,1931 ****
    if (flag_indirect_dispatch)
      {
!       otable_index = build_int_2 (get_offset_table_index (method), 0);
        idx = build (ARRAY_REF, integer_type_node, otable_decl, otable_index);
      }
--- 1958,1963 ----
    if (flag_indirect_dispatch)
      {
!       otable_index 
! 	= build_int_2 (get_symbol_table_index (method, &otable_methods), 0);
        idx = build (ARRAY_REF, integer_type_node, otable_decl, otable_index);
      }
Index: gcc/java/java-tree.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/java/java-tree.h,v
retrieving revision 1.183
diff -c -2 -p -r1.183 java-tree.h
*** gcc/java/java-tree.h	3 Sep 2003 13:44:43 -0000	1.183
--- gcc/java/java-tree.h	25 Sep 2003 17:59:08 -0000
*************** extern int compiling_from_source;
*** 150,153 ****
--- 150,154 ----
     generate virtual method offset symbol table. */
  #define otable_methods java_global_trees [JTI_OTABLE_METHODS]
+ #define atable_methods java_global_trees [JTI_ATABLE_METHODS]
  
  /* The virtual method offset table. This is emitted as uninitialized data of 
*************** extern int compiling_from_source;
*** 155,161 ****
--- 156,165 ----
  #define otable_decl java_global_trees [JTI_OTABLE_DECL]
  
+ #define atable_decl java_global_trees [JTI_ATABLE_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]
+ #define atable_syms_decl java_global_trees [JTI_ATABLE_SYMS_DECL]
  
  extern int flag_emit_class_files;
*************** enum java_tree_index
*** 365,371 ****
    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,
--- 369,377 ----
    JTI_OTABLE_TYPE,
    JTI_OTABLE_PTR_TYPE,
!   JTI_ATABLE_TYPE,
!   JTI_ATABLE_PTR_TYPE,
!   JTI_SYMBOL_TYPE,
!   JTI_SYMBOLS_ARRAY_TYPE,
!   JTI_SYMBOLS_ARRAY_PTR_TYPE,
  
    JTI_END_PARAMS_NODE,
*************** enum java_tree_index
*** 410,413 ****
--- 416,423 ----
    JTI_OTABLE_SYMS_DECL,
  
+   JTI_ATABLE_METHODS,
+   JTI_ATABLE_DECL,
+   JTI_ATABLE_SYMS_DECL,
+ 
    JTI_PREDEF_FILENAMES,
  
*************** extern GTY(()) tree java_global_trees[JT
*** 603,614 ****
  #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 \
--- 613,628 ----
  #define otable_type \
    java_global_trees[JTI_OTABLE_TYPE]
+ #define atable_type \
+   java_global_trees[JTI_ATABLE_TYPE]
  #define otable_ptr_type \
    java_global_trees[JTI_OTABLE_PTR_TYPE]
! #define atable_ptr_type \
!   java_global_trees[JTI_ATABLE_PTR_TYPE]
! #define symbol_type \
!   java_global_trees[JTI_SYMBOL_TYPE]
! #define symbols_array_type \
!   java_global_trees[JTI_SYMBOLS_ARRAY_TYPE]
! #define symbols_array_ptr_type \
!   java_global_trees[JTI_SYMBOLS_ARRAY_PTR_TYPE]
  
  #define end_params_node \
*************** extern void register_class (void);
*** 1200,1204 ****
  extern int alloc_name_constant (int, tree);
  extern void emit_register_classes (void);
! extern void emit_offset_symbol_table (void);
  extern void lang_init_source (int);
  extern void write_classfile (tree);
--- 1214,1218 ----
  extern int alloc_name_constant (int, tree);
  extern void emit_register_classes (void);
! extern tree emit_symbol_table (tree, tree, tree, tree, tree);
  extern void lang_init_source (int);
  extern void write_classfile (tree);
*************** extern void start_complete_expand_method
*** 1301,1304 ****
--- 1315,1319 ----
  extern void java_expand_body (tree);
  
+ extern int get_symbol_table_index (tree, tree *);
  
  #define DECL_FINAL(DECL) DECL_LANG_FLAG_3 (DECL)
*************** extern tree *type_map;
*** 1660,1668 ****
     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. */
--- 1675,1683 ----
     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. */
Index: gcc/java/jcf-parse.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/java/jcf-parse.c,v
retrieving revision 1.145
diff -c -2 -p -r1.145 jcf-parse.c
*** gcc/java/jcf-parse.c	22 Sep 2003 05:09:31 -0000	1.145
--- gcc/java/jcf-parse.c	25 Sep 2003 17:59:08 -0000
*************** java_parse_file (int set_yydebug ATTRIBU
*** 1130,1134 ****
        emit_register_classes ();
        if (flag_indirect_dispatch)
! 	emit_offset_symbol_table ();
      }
  
--- 1130,1143 ----
        emit_register_classes ();
        if (flag_indirect_dispatch)
! 	{
! 	  otable_decl 
! 	    = emit_symbol_table 
! 	    (get_identifier ("otable"), 
! 	     otable_decl, otable_methods, otable_syms_decl, integer_type_node);
! 	  atable_decl 
! 	    = emit_symbol_table 
! 	    (get_identifier ("atable"), 
! 	     atable_decl, atable_methods, atable_syms_decl, ptr_type_node);
! 	}
      }
  
2003-09-24  Andrew Haley  <aph@redhat.com>

	* java/lang/natClass.cc (initializeClass): Check for otable and
	atable.
	(_Jv_LinkOffsetTable): Check for existence of atable.  Rewrite
	loops using for().  Search superinterfaces.  Check for fields as
	well as methods.  Initialize atable as well as otable: check for
	static methods as well as virtual methods.
	* java/lang/Class.h (struct _Jv_AddressTable): New.
	(atable): New.
	(atable_syms): New.
	* include/jvm.h (_Jv_equalUtf8Consts): constify.
	* prims.cc (_Jv_equalUtf8Consts): constify.

Index: libjava/prims.cc
===================================================================
RCS file: /cvs/gcc/gcc/libjava/prims.cc,v
retrieving revision 1.82
diff -c -2 -p -r1.82 prims.cc
*** libjava/prims.cc	20 Aug 2003 14:32:15 -0000	1.82
--- libjava/prims.cc	25 Sep 2003 17:59:15 -0000
*************** SIGNAL_HANDLER (catch_fpe)
*** 166,173 ****
  
  jboolean
! _Jv_equalUtf8Consts (Utf8Const* a, Utf8Const *b)
  {
    int len;
!   _Jv_ushort *aptr, *bptr;
    if (a == b)
      return true;
--- 166,173 ----
  
  jboolean
! _Jv_equalUtf8Consts (const Utf8Const* a, const Utf8Const *b)
  {
    int len;
!   const _Jv_ushort *aptr, *bptr;
    if (a == b)
      return true;
*************** _Jv_equalUtf8Consts (Utf8Const* a, Utf8C
*** 177,182 ****
    if (b->length != len)
      return false;
!   aptr = (_Jv_ushort *)a->data;
!   bptr = (_Jv_ushort *)b->data;
    len = (len + 1) >> 1;
    while (--len >= 0)
--- 177,182 ----
    if (b->length != len)
      return false;
!   aptr = (const _Jv_ushort *)a->data;
!   bptr = (const _Jv_ushort *)b->data;
    len = (len + 1) >> 1;
    while (--len >= 0)
Index: libjava/include/jvm.h
===================================================================
RCS file: /cvs/gcc/gcc/libjava/include/jvm.h,v
retrieving revision 1.59
diff -c -2 -p -r1.59 jvm.h
*** libjava/include/jvm.h	28 Aug 2003 22:17:36 -0000	1.59
--- libjava/include/jvm.h	25 Sep 2003 17:59:15 -0000
*************** typedef struct _Jv_Utf8Const Utf8Const;
*** 146,150 ****
  _Jv_Utf8Const *_Jv_makeUtf8Const (char *s, int len);
  _Jv_Utf8Const *_Jv_makeUtf8Const (jstring string);
! extern jboolean _Jv_equalUtf8Consts (_Jv_Utf8Const *, _Jv_Utf8Const *);
  extern jboolean _Jv_equal (_Jv_Utf8Const *, jstring, jint);
  extern jboolean _Jv_equaln (_Jv_Utf8Const *, jstring, jint);
--- 146,150 ----
  _Jv_Utf8Const *_Jv_makeUtf8Const (char *s, int len);
  _Jv_Utf8Const *_Jv_makeUtf8Const (jstring string);
! extern jboolean _Jv_equalUtf8Consts (const _Jv_Utf8Const *, const _Jv_Utf8Const *);
  extern jboolean _Jv_equal (_Jv_Utf8Const *, jstring, jint);
  extern jboolean _Jv_equaln (_Jv_Utf8Const *, jstring, jint);
Index: libjava/java/lang/Class.h
===================================================================
RCS file: /cvs/gcc/gcc/libjava/java/lang/Class.h,v
retrieving revision 1.58
diff -c -2 -p -r1.58 Class.h
*** libjava/java/lang/Class.h	25 Sep 2003 07:46:19 -0000	1.58
--- libjava/java/lang/Class.h	25 Sep 2003 17:59:15 -0000
*************** struct _Jv_OffsetTable
*** 126,129 ****
--- 126,135 ----
  };
  
+ struct _Jv_AddressTable
+ {
+   jint state;
+   void *addresses[];
+ };
+ 
  #define JV_PRIMITIVE_VTABLE ((_Jv_VTable *) -1)
  
*************** private:   
*** 325,329 ****
    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 *, jboolean *);
--- 331,335 ----
    friend jshort _Jv_AppendPartialITable (jclass, jclass, void **, jshort);
    friend jshort _Jv_FindIIndex (jclass *, jshort *, jshort);
!   friend void _Jv_LinkSymbolTable (jclass);
    friend void _Jv_LayoutVTableMethods (jclass klass);
    friend void _Jv_SetVTableEntries (jclass, _Jv_VTable *, jboolean *);
*************** private:   
*** 405,408 ****
--- 411,416 ----
    // Offset table symbols.
    _Jv_MethodSymbol *otable_syms;
+   _Jv_AddressTable *atable;
+   _Jv_MethodSymbol *atable_syms;
    // 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.64
diff -c -2 -p -r1.64 natClass.cc
*** libjava/java/lang/natClass.cc	25 Sep 2003 07:46:19 -0000	1.64
--- libjava/java/lang/natClass.cc	25 Sep 2003 17:59:16 -0000
*************** details.  */
*** 37,40 ****
--- 37,41 ----
  #include <java/lang/IllegalArgumentException.h>
  #include <java/lang/IncompatibleClassChangeError.h>
+ #include <java/lang/NoSuchFieldError.h>
  #include <java/lang/ArrayIndexOutOfBoundsException.h>
  #include <java/lang/InstantiationException.h>
*************** java::lang::Class::initializeClass (void
*** 791,795 ****
        _Jv_PrepareConstantTimeTables (this);
        _Jv_MakeVTable(this);
!       _Jv_LinkOffsetTable(this);
  
        return;
--- 792,796 ----
        _Jv_PrepareConstantTimeTables (this);
        _Jv_MakeVTable(this);
!       _Jv_LinkSymbolTable(this);
  
        return;
*************** java::lang::Class::initializeClass (void
*** 831,836 ****
      _Jv_MakeVTable(this);
  
!   if (otable != NULL && otable->state == 0)
!     _Jv_LinkOffsetTable(this);
  
    // Steps 8, 9, 10, 11.
--- 832,837 ----
      _Jv_MakeVTable(this);
  
!   if (otable || atable)
!     _Jv_LinkSymbolTable(this);
  
    // Steps 8, 9, 10, 11.
*************** java::lang::Class::getProtectionDomain0 
*** 1534,1606 ****
  }
  
! // 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];
      }
  }
--- 1535,1767 ----
  }
  
! // Functions for indirect dispatch (symbolic virtual binding) support.
! 
! // There are two tables, atable and otable.  atable is an array of
! // addresses, and otable is an array of offsets, and these are used
! // for static and virtual members respectively.
! 
! // {a,o}table_syms is an array of _Jv_MethodSymbols.  Each such symbol
! // is a tuple of {classname, member name, signature}.
! // _Jv_LinkSymbolTable() scans these two arrays and fills in the
! // corresponding atable and otable with the addresses of static
! // members and the offsets of virtual members.
! 
! // The offset (in bytes) for each resolved method or field is placed
! // at the corresponding position in the virtual method offset table
! // (klass->otable). 
! 
! // The same otable and atable may be shared by many classes.
  
  void
! _Jv_LinkSymbolTable(jclass klass)
  {
!   //// FIXME: Need to lock the tables ////
    
+   int index = 0;
+   _Jv_MethodSymbol sym;
    if (klass->otable == NULL
        || klass->otable->state != 0)
!     goto atable;
!    
    klass->otable->state = 1;
  
!   for (index = 0; sym = klass->otable_syms[index], sym.name != NULL; index++)
      {
        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;
        
!       if (target_class == NULL)
! 	continue;
! 
!       if (target_class->isInterface())
! 	{
! 	  for (jclass cls = target_class; cls != 0; cls = cls->getSuperclass ())
! 	    {
! 	      for (int i=0; i < cls->method_count; i++)
! 		{
! 		  meth = &cls->methods[i];
! 		  if (_Jv_equalUtf8Consts (sym.name, meth->name)
! 		      && _Jv_equalUtf8Consts (signature, meth->signature))
! 		    {
! 		      klass->otable->offsets[index] = i + 1;
! 		      goto found;
! 		    }
! 		}
! 	    
! 	    }
! 	found:
! 	  continue;
! 	}
! 
!       // We're looking for a field or a method, and we can tell
!       // which is needed by looking at the signature.
!       if (signature->length >= 2
! 	  && signature->data[0] == '(')
! 	{
!  	  // 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);	      
! 	    }
! 
! 	  continue;
! 	}
! 
!       // try fields
!       {
! 	_Jv_Field *the_field = NULL;
! 
! 	for (jclass cls = target_class; cls != 0; cls = cls->getSuperclass ())
  	  {
! 	    for (int i = 0; i < cls->field_count; i++)
  	      {
! 		_Jv_Field *field = &cls->fields[i];
! 		if (! _Jv_equalUtf8Consts (field->name, sym.name))
! 		  continue;
! 
! 		// FIXME: What access checks should we perform here?
! // 		if (_Jv_CheckAccess (klass, cls, field->flags))
! // 		  {
! 
! 		if (!field->isResolved ())
! 		  _Jv_ResolveField (field, cls->loader);
! 
! // 		if (field_type != 0 && field->type != field_type)
! // 		  throw new java::lang::LinkageError
! // 		    (JvNewStringLatin1 
! // 		     ("field type mismatch with different loaders"));
! 
! 		the_field = field;
! 		goto end_of_field_search;
  	      }
  	  }
!       end_of_field_search:
! 	if (the_field != NULL)
  	  {
! 	    if (the_field->flags & 0x0008 /* Modifier::STATIC */)
! 	      {	      
! 		throw new java::lang::IncompatibleClassChangeError;
! 	      }
! 	    else
  	      {
! 		klass->otable->offsets[index] = the_field->u.boffset;
  	      }
+ 	  }
+ 	else
+ 	  {
+ 	    throw new java::lang::NoSuchFieldError
+ 	      (_Jv_NewStringUtf8Const (sym.name));
+ 	  }
+       }
+     }
+ 
+  atable:
+   if (klass->atable == NULL
+       || klass->atable->state != 0)
+     return;
+ 
+   klass->atable->state = 1;
+ 
+   for (index = 0; sym = klass->atable_syms[index], sym.name != NULL; index++)
+     {
+       jclass target_class = _Jv_FindClass (sym.class_name, NULL);
+       _Jv_Method *meth = NULL;            
+       const _Jv_Utf8Const *signature = sym.signature;
+ 
+       // ??? Setting this pointer to null will at least get us a
+       // NullPointerException
+       klass->atable->addresses[index] = NULL;
+       
+       if (target_class == NULL)
+ 	continue;
+       
+       // We're looking for a static field or a static method, and we
+       // can tell which is needed by looking at the signature.
+       if (signature->length >= 2
+ 	  && signature->data[0] == '(')
+ 	{
+  	  // 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->atable->addresses[index] = meth->ncode;
+ 	  else
+ 	    klass->atable->addresses[index] = (void *)_Jv_ThrowNoSuchMethodError;
+ 
+ 	  continue;
+ 	}
  
!       // try fields
!       {
! 	_Jv_Field *the_field = NULL;
  
! 	for (jclass cls = target_class; cls != 0; cls = cls->getSuperclass ())
! 	  {
! 	    for (int i = 0; i < cls->field_count; i++)
  	      {
! 		_Jv_Field *field = &cls->fields[i];
! 		if (! _Jv_equalUtf8Consts (field->name, sym.name))
! 		  continue;
! 
! 		// FIXME: What access checks should we perform here?
! // 		if (_Jv_CheckAccess (klass, cls, field->flags))
! // 		  {
! 
! 		if (!field->isResolved ())
! 		  _Jv_ResolveField (field, cls->loader);
! 		
! // 		if (field_type != 0 && field->type != field_type)
! // 		  throw new java::lang::LinkageError
! // 		    (JvNewStringLatin1 
! // 		     ("field type mismatch with different loaders"));
! 
! 		the_field = field;
! 		goto end_of_static_field_search;
  	      }
  	  }
!       end_of_static_field_search:
! 	if (the_field != NULL)
! 	  {
! 	    if (the_field->flags & 0x0008 /* Modifier::STATIC */)
! 	      {	      
! 		klass->atable->addresses[index] = the_field->u.addr;
! 	      }
! 	    else
! 	      {
! 		throw new java::lang::IncompatibleClassChangeError;
! 	      }
! 	  }
! 	else
! 	  {
! 	    throw new java::lang::NoSuchFieldError
! 	      (_Jv_NewStringUtf8Const (sym.name));
! 	  }
!       }
      }
  }
Index: libjava/testsuite/libjava.lang/lang.exp
===================================================================
RCS file: /cvs/gcc/gcc/libjava/testsuite/libjava.lang/lang.exp,v
retrieving revision 1.3
diff -c -2 -p -r1.3 lang.exp
*** libjava/testsuite/libjava.lang/lang.exp	5 Sep 2003 01:53:47 -0000	1.3
--- libjava/testsuite/libjava.lang/lang.exp	25 Sep 2003 17:59:16 -0000
*************** foreach x $srcfiles {
*** 28,31 ****
--- 28,32 ----
  
      test_libjava $options "${prefix}.java" "" $inpfile $resfile $args
+     test_libjava $options "${prefix}.java" "-findirect-dispatch" $inpfile $resfile $args
      test_libjava $options "${prefix}.java" "-O3" $inpfile $resfile $args
  }



More information about the Gcc-patches mailing list