This is the mail archive of the java-patches@gcc.gnu.org mailing list for the Java project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Re: PR java/19285: Interfaces not initialized by static field access


This is the compile time part of the patch.

The idea is that rather than calling _Jv_InitClass for every static
field we call _Jv_ResolvePoolEntry instead.  We also cache these
locally so that _Jv_ResolvePoolEntry is only called once.  This
generates fairly good code, but some more optimization is possible.

Andrew.


2005-04-28  Andrew Haley  <aph@redhat.com>

	PR java/19285
	* java-tree.h (soft_resolvepoolentry_node): New.
	(alloc_constant_fieldref): Declare.
	* expr.c (expand_java_field_op): Don't call class_init for
	accesses to static fields with indirect dispatch.
	* builtins.c (initialize_builtins): Add "__builtin_expect".
	* decl.c (soft_resolvepoolentry_node): New variable.
	(java_init_decl_processing): Create a decl for
	"_Jv_ResolvePoolEntry".
	* class.c (build_fieldref_cache_entry): New function.
	* class.c (build_static_field_ref): New function.
	(build_static_field_ref): Rewrite for indirect dispatch.
	* constants.c (find_name_and_type_constant_tree): New function.
	(alloc_constant_fieldref): Likewise.
	(build_constants_constructor): Handle CONSTANT_Fieldref and
	CONSTANT_NameAndType.

Index: builtins.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/java/builtins.c,v
retrieving revision 1.29
diff -c -2 -p -r1.29 builtins.c
*** builtins.c	12 Feb 2005 15:21:13 -0000	1.29
--- builtins.c	28 Apr 2005 17:12:17 -0000
*************** initialize_builtins (void)
*** 162,165 ****
--- 162,166 ----
    tree double_ftype_double, double_ftype_double_double;
    tree float_ftype_float, float_ftype_float_float;
+   tree boolean_ftype_boolean_boolean;
    tree t;
    int i;
*************** initialize_builtins (void)
*** 217,221 ****
    define_builtin (BUILT_IN_TAN, "__builtin_tan",
  		  double_ftype_double, "_ZN4java4lang4Math3tanEd");
! 
    build_common_builtin_nodes ();
  }
--- 218,229 ----
    define_builtin (BUILT_IN_TAN, "__builtin_tan",
  		  double_ftype_double, "_ZN4java4lang4Math3tanEd");
!   
!   t = tree_cons (NULL_TREE, boolean_type_node, end_params_node);
!   t = tree_cons (NULL_TREE, boolean_type_node, t);
!   boolean_ftype_boolean_boolean = build_function_type (boolean_type_node, t);
!   define_builtin (BUILT_IN_EXPECT, "__builtin_expect", 
! 		  boolean_ftype_boolean_boolean,
! 		  "__builtin_expect");
! 		  
    build_common_builtin_nodes ();
  }
Index: class.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/java/class.c,v
retrieving revision 1.223
diff -c -2 -p -r1.223 class.c
*** class.c	7 Apr 2005 19:12:52 -0000	1.223
--- class.c	28 Apr 2005 17:12:18 -0000
*************** build_class_ref (tree type)
*** 1038,1041 ****
--- 1038,1066 ----
  }
  
+ /* Create a local statically allocated variable that will hold a
+    pointer to a static field.  */
+ 
+ static tree
+ build_fieldref_cache_entry (int index, tree fdecl ATTRIBUTE_UNUSED)
+ {
+   tree decl, decl_name;
+   const char *name = IDENTIFIER_POINTER (mangled_classname ("_cpool_", output_class));
+   char *buf = alloca (strlen (name) + 20);
+   sprintf (buf, "%s_%d_ref", name, index);
+   decl_name = get_identifier (buf);
+   decl = IDENTIFIER_GLOBAL_VALUE (decl_name);
+   if (decl == NULL_TREE)
+     {
+       decl = build_decl (VAR_DECL, decl_name, ptr_type_node);
+       TREE_STATIC (decl) = 1;
+       TREE_PUBLIC (decl) = 0;
+       DECL_EXTERNAL (decl) = 0;
+       DECL_ARTIFICIAL (decl) = 1;
+       make_decl_rtl (decl);
+       pushdecl_top_level (decl);
+     }
+   return decl;
+ }
+ 
  tree
  build_static_field_ref (tree fdecl)
*************** build_static_field_ref (tree fdecl)
*** 1063,1119 ****
  	  make_decl_rtl (fdecl);
  	}
-       return fdecl;
      }
! 
!   if (flag_indirect_dispatch)
      {
!       tree table_index 
! 	= build_int_cst (NULL_TREE, get_symbol_table_index 
! 			 (fdecl, &TYPE_ATABLE_METHODS (output_class)));
!       tree field_address
! 	= build4 (ARRAY_REF, 
! 		  TREE_TYPE (TREE_TYPE (TYPE_ATABLE_DECL (output_class))), 
! 		  TYPE_ATABLE_DECL (output_class), table_index,
! 		  NULL_TREE, NULL_TREE);
!       field_address = convert (build_pointer_type (TREE_TYPE (fdecl)),
! 			       field_address);
!       return fold (build1 (INDIRECT_REF, TREE_TYPE (fdecl), 
! 			   field_address));
!     }
!   else  
!     {
!       /* Compile as:
!        *(FTYPE*)build_class_ref(FCLASS)->fields[INDEX].info.addr */
!       tree ref = build_class_ref (fclass);
!       tree fld;
!       int field_index = 0;
!       ref = build1 (INDIRECT_REF, class_type_node, ref);
!       ref = build3 (COMPONENT_REF, field_ptr_type_node, ref,
! 		    lookup_field (&class_type_node, fields_ident),
! 		    NULL_TREE);
! 
!       for (fld = TYPE_FIELDS (fclass); ; fld = TREE_CHAIN (fld))
! 	{
! 	  if (fld == fdecl)
! 	    break;
! 	  if (fld == NULL_TREE)
! 	    fatal_error ("field '%s' not found in class",
! 			 IDENTIFIER_POINTER (DECL_NAME (fdecl)));
! 	  if (FIELD_STATIC (fld))
! 	    field_index++;
! 	}
!       field_index *= int_size_in_bytes (field_type_node);
!       ref = fold (build2 (PLUS_EXPR, field_ptr_type_node,
! 			  ref, build_int_cst (NULL_TREE, field_index)));
!       ref = build1 (INDIRECT_REF, field_type_node, ref);
!       ref = build3 (COMPONENT_REF, field_info_union_node,
! 		    ref, lookup_field (&field_type_node, info_ident), 
! 		    NULL_TREE);
!       ref = build3 (COMPONENT_REF, ptr_type_node,
! 		    ref, TREE_CHAIN (TYPE_FIELDS (field_info_union_node)),
! 		    NULL_TREE);
!       ref = build1 (NOP_EXPR, build_pointer_type (TREE_TYPE (fdecl)), ref);
!       return fold (build1 (INDIRECT_REF, TREE_TYPE(fdecl), ref));
      }
  }
  
--- 1088,1132 ----
  	  make_decl_rtl (fdecl);
  	}
      }
!   else
      {
!       /* Generate a CONSTANT_FieldRef for FDECL in the constant pool
! 	 and a class local static variable CACHE_ENTRY, then
!       
!       *(fdecl **)((__builtin_expect (cache_entry == null, false)) 
! 		  ? cache_entry = _Jv_ResolvePoolEntry (output_class, cpool_index)
! 		  : cache_entry)
! 
!       This can mostly be optimized away, so that the usual path is a
!       load followed by a test and branch.  _Jv_ResolvePoolEntry is
!       only called once for each constant pool entry.
! 
!       There is an optimization that we don't do: at the start of a
!       method, create a local copy of CACHE_ENTRY and use that instead.
! 
!       */
! 
!       int cpool_index = alloc_constant_fieldref (output_class, fdecl);
!       tree cache_entry = build_fieldref_cache_entry (cpool_index, fdecl);
!       tree test 
! 	= build3 (CALL_EXPR, boolean_type_node, 
! 		  build_address_of (built_in_decls[BUILT_IN_EXPECT]),
! 		  tree_cons (NULL_TREE, build2 (EQ_EXPR, boolean_type_node,
! 						cache_entry, null_pointer_node),
! 			     build_tree_list (NULL_TREE, boolean_false_node)),
! 		  NULL_TREE);
!       tree cpool_index_cst = build_int_cst (NULL_TREE, cpool_index);
!       tree init
! 	= build3 (CALL_EXPR, ptr_type_node,
! 		  build_address_of (soft_resolvepoolentry_node),
! 		  tree_cons (NULL_TREE, build_class_ref (output_class),
! 			     build_tree_list (NULL_TREE, cpool_index_cst)),
! 		  NULL_TREE);
!       init = build2 (MODIFY_EXPR, ptr_type_node, cache_entry, init);
!       init = build3 (COND_EXPR, ptr_type_node, test, init, cache_entry);
!       init = fold_convert (build_pointer_type (TREE_TYPE (fdecl)), init);
!       fdecl = build1 (INDIRECT_REF, TREE_TYPE (fdecl), init);
      }
+   return fdecl;
  }
  
Index: constants.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/java/constants.c,v
retrieving revision 1.40
diff -c -2 -p -r1.40 constants.c
*** constants.c	25 Aug 2004 09:52:50 -0000	1.40
--- constants.c	28 Apr 2005 17:12:18 -0000
*************** alloc_name_constant (int tag, tree name)
*** 357,360 ****
--- 357,395 ----
  }
  
+ /* Create a cinstant pool entry for a name_and_type.  This one has '.'
+    rather than '/' because it isn't going into a class file, it's
+    going into a compiled object.  We don't use the '/' separator in
+    compiled objects.  */
+ 
+ static int
+ find_name_and_type_constant_tree (CPool *cpool, tree name, tree type)
+ {
+   int name_index = find_utf8_constant (cpool, name);
+   int type_index 
+     = find_utf8_constant (cpool, 
+ 			  identifier_subst (build_java_signature (type), 
+ 					    "", '/', '.', ""));
+   return find_constant1 (cpool, CONSTANT_NameAndType,
+ 			 (name_index << 16) | type_index);
+ }
+ 
+ /* Look for a field ref that matches DECL in the constant pool of
+    CLASS.  
+    Return the index of the entry.  */
+ 
+ int
+ alloc_constant_fieldref (tree class, tree decl)
+ {
+   CPool *outgoing_cpool = cpool_for_class (class);
+   int class_index 
+     = find_tree_constant (outgoing_cpool, CONSTANT_Class, 
+ 			  DECL_NAME (TYPE_NAME (DECL_CONTEXT (decl))));
+   int name_type_index
+     = find_name_and_type_constant_tree (outgoing_cpool, DECL_NAME (decl), 
+ 					TREE_TYPE (decl));
+   return find_constant1 (outgoing_cpool, CONSTANT_Fieldref,
+ 			 (class_index << 16) | name_type_index);
+ }
+ 
  /* Build an identifier for the internal name of reference type TYPE. */
  
*************** build_constants_constructor (void)
*** 443,454 ****
    int i;
    for (i = outgoing_cpool->count;  --i > 0; )
!     {
!       tags_list
! 	= tree_cons (NULL_TREE, get_tag_node (outgoing_cpool->tags[i]),
! 		     tags_list);
!       data_list
! 	= tree_cons (NULL_TREE, build_utf8_ref (outgoing_cpool->data[i].t),
! 		     data_list);
!     }
    if (outgoing_cpool->count > 0)
      {
--- 478,508 ----
    int i;
    for (i = outgoing_cpool->count;  --i > 0; )
!     switch (outgoing_cpool->tags[i])
!       {
!       case CONSTANT_Fieldref:
!       case CONSTANT_NameAndType:
! 	{
! 	  jword temp = outgoing_cpool->data[i].w;
! 
! 	  tags_list
! 	    = tree_cons (NULL_TREE, 
! 			 build_int_cst (NULL_TREE, outgoing_cpool->tags[i]),
! 			 tags_list);
! 	  data_list
! 	    = tree_cons (NULL_TREE, 
! 			 fold_convert (ptr_type_node, 
! 				       (build_int_cst (NULL_TREE, temp))),
! 			 data_list);
! 	}
! 	break;
!       default:
! 	tags_list
! 	  = tree_cons (NULL_TREE, get_tag_node (outgoing_cpool->tags[i]),
! 		       tags_list);
! 	data_list
! 	  = tree_cons (NULL_TREE, build_utf8_ref (outgoing_cpool->data[i].t),
! 		       data_list);
! 	break;
!       }
    if (outgoing_cpool->count > 0)
      {
*************** build_constants_constructor (void)
*** 462,466 ****
    
        data_decl = build_constant_data_ref ();
!       TREE_TYPE (data_decl) = build_array_type (ptr_type_node, index_type), 
        DECL_INITIAL (data_decl) = build_constructor (TREE_TYPE (data_decl),
  						    data_list);
--- 516,520 ----
    
        data_decl = build_constant_data_ref ();
!       TREE_TYPE (data_decl) = build_array_type (ptr_type_node, index_type);
        DECL_INITIAL (data_decl) = build_constructor (TREE_TYPE (data_decl),
  						    data_list);
Index: decl.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/java/decl.c,v
retrieving revision 1.218
diff -c -2 -p -r1.218 decl.c
*** decl.c	23 Apr 2005 21:29:01 -0000	1.218
--- decl.c	28 Apr 2005 17:12:18 -0000
*************** static int uniq;
*** 105,108 ****
--- 105,111 ----
  static GTY(()) tree pending_local_decls;
  
+ /* The decl for "_Jv_ResolvePoolEntry".  */
+ tree soft_resolvepoolentry_node;
+ 
  #if defined(DEBUG_JAVA_BINDING_LEVELS)
  int binding_depth = 0;
*************** java_init_decl_processing (void)
*** 1016,1020 ****
  							       t),
  					  0, NOT_BUILT_IN, NULL, NULL_TREE);
! 
    throw_node = builtin_function ("_Jv_Throw",
  				 build_function_type (void_type_node, t),
--- 1019,1029 ----
  							       t),
  					  0, NOT_BUILT_IN, NULL, NULL_TREE);
!   t = tree_cons (NULL_TREE, class_ptr_type,
! 		 tree_cons (NULL_TREE, int_type_node, endlink));
!   soft_resolvepoolentry_node 
!     = builtin_function ("_Jv_ResolvePoolEntry", 
! 			build_function_type (ptr_type_node, t),
! 			0,NOT_BUILT_IN, NULL, NULL_TREE);
!   DECL_IS_PURE (soft_resolvepoolentry_node) = 1;
    throw_node = builtin_function ("_Jv_Throw",
  				 build_function_type (void_type_node, t),
Index: expr.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/java/expr.c,v
retrieving revision 1.221
diff -c -2 -p -r1.221 expr.c
*** expr.c	17 Mar 2005 14:43:26 -0000	1.221
--- expr.c	28 Apr 2005 17:12:19 -0000
*************** expand_java_field_op (int is_static, int
*** 2716,2720 ****
  
    field_ref = build_field_ref (field_ref, self_type, field_name);
!   if (is_static)
      field_ref = build_class_init (self_type, field_ref);
    if (is_putting)
--- 2716,2721 ----
  
    field_ref = build_field_ref (field_ref, self_type, field_name);
!   if (is_static
!       && ! flag_indirect_dispatch)
      field_ref = build_class_init (self_type, field_ref);
    if (is_putting)
*************** maybe_adjust_start_pc (struct JCF *jcf, 
*** 3485,3489 ****
     left-to-right order evaluation is performed. Saved expressions
     will, in CALL_EXPR order, be reused when the call will be expanded.
! */
  
  tree
--- 3486,3491 ----
     left-to-right order evaluation is performed. Saved expressions
     will, in CALL_EXPR order, be reused when the call will be expanded.
! 
!    We also promote outgoing args if needed.  */
  
  tree
*************** force_evaluation_order (tree node)
*** 3519,3522 ****
--- 3521,3533 ----
        for (cmp = NULL_TREE; arg; arg = TREE_CHAIN (arg))
  	{
+ 	  /* Promote types smaller than integer.  This is required by
+ 	     some ABIs.  */
+ 	  tree type = TREE_TYPE (TREE_VALUE (arg));
+ 	  if (targetm.calls.promote_prototypes (type)
+ 	      && INTEGRAL_TYPE_P (type)
+ 	      && INT_CST_LT_UNSIGNED (TYPE_SIZE (type),
+ 				      TYPE_SIZE (integer_type_node)))
+ 	    TREE_VALUE (arg) = fold_convert (integer_type_node, TREE_VALUE (arg));
+ 
  	  tree saved = save_expr (force_evaluation_order (TREE_VALUE (arg)));
  	  cmp = (cmp == NULL_TREE ? saved :
Index: java-tree.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/java/java-tree.h,v
retrieving revision 1.229
diff -c -2 -p -r1.229 java-tree.h
*** java-tree.h	8 Apr 2005 01:02:59 -0000	1.229
--- java-tree.h	28 Apr 2005 17:12:20 -0000
*************** extern GTY(()) tree java_global_trees[JT
*** 687,690 ****
--- 687,692 ----
    java_global_trees[JTI_WFL_OPERATOR]
  
+ extern GTY(()) tree soft_resolvepoolentry_node;
+ 
  extern const char *cyclic_inheritance_report;
  
*************** union lang_tree_node 
*** 804,807 ****
--- 806,810 ----
     Actually each TREE_VALUE points to a COMPONT_EXPR that wraps the
     invocation so we can later patch it.  */
+ 
  #define DECL_FUNCTION_STATIC_METHOD_INVOCATION_COMPOUND(DECL) \
    (DECL_LANG_SPECIFIC(DECL)->u.f.smic)
*************** struct lang_decl GTY(())
*** 1098,1101 ****
--- 1101,1105 ----
  #define TYPE_ASSERTIONS(T)   	 (TYPE_LANG_SPECIFIC (T)->type_assertions)
  
+ 
  struct lang_type GTY(())
  {
*************** extern void make_class_data (tree);
*** 1286,1289 ****
--- 1290,1294 ----
  extern void register_class (void);
  extern int alloc_name_constant (int, tree);
+ extern int alloc_constant_fieldref (tree, tree);
  extern void emit_register_classes (tree *);
  extern tree emit_symbol_table (tree, tree, tree, tree, tree, int);


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