This is the mail archive of the
java-patches@gcc.gnu.org
mailing list for the Java project.
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);