re PR java/19285 (Interfaces not initialized by static field access)

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.
        (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.

        PR java/21115
        * expr.c (force_evaluation_order): Convert outgoing args smaller
        than integer.

From-SVN: r99010
This commit is contained in:
Andrew Haley 2005-04-29 18:43:25 +00:00 committed by Andrew Haley
parent a68b179c86
commit 2c80f01549
7 changed files with 183 additions and 62 deletions

View file

@ -1,3 +1,25 @@
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.
(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.
PR java/21115
* expr.c (force_evaluation_order): Convert outgoing args smaller
than integer.
2005-04-27 Bryce McKinlay <mckinlay@redhat.com>
* gcj.texi (libgcj Runtime Properties): Remove obsolete

View file

@ -161,6 +161,7 @@ initialize_builtins (void)
{
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;
@ -216,7 +217,14 @@ initialize_builtins (void)
double_ftype_double, "_ZN4java4lang4Math4sqrtEd");
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 ();
}

View file

@ -1037,6 +1037,31 @@ build_class_ref (tree type)
return build_indirect_class_ref (type);
}
/* 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)
{
@ -1062,59 +1087,47 @@ build_static_field_ref (tree fdecl)
DECL_EXTERNAL (fdecl) = 1;
make_decl_rtl (fdecl);
}
return fdecl;
}
if (flag_indirect_dispatch)
else
{
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);
/* 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)
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));
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;
}
int

View file

@ -356,6 +356,41 @@ alloc_name_constant (int tag, tree name)
return find_tree_constant (outgoing_cpool, tag, name);
}
/* Create a constant 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. */
tree
@ -442,14 +477,33 @@ build_constants_constructor (void)
tree data_list = NULL_TREE;
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);
}
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)
{
tree data_decl, tags_decl, tags_type;
@ -461,7 +515,7 @@ build_constants_constructor (void)
data_list = tree_cons (NULL_TREE, null_pointer_node, data_list);
data_decl = build_constant_data_ref ();
TREE_TYPE (data_decl) = build_array_type (ptr_type_node, index_type),
TREE_TYPE (data_decl) = build_array_type (ptr_type_node, index_type);
DECL_INITIAL (data_decl) = build_constructor (TREE_TYPE (data_decl),
data_list);
DECL_SIZE (data_decl) = TYPE_SIZE (TREE_TYPE (data_decl));

View file

@ -104,6 +104,9 @@ static int uniq;
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;
int is_class_level = 0;
@ -1015,7 +1018,13 @@ java_init_decl_processing (void)
build_function_type (void_type_node,
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),
0, NOT_BUILT_IN, NULL, NULL_TREE);

View file

@ -2715,7 +2715,8 @@ expand_java_field_op (int is_static, int is_putting, int field_ref_index)
}
field_ref = build_field_ref (field_ref, self_type, field_name);
if (is_static)
if (is_static
&& ! flag_indirect_dispatch)
field_ref = build_class_init (self_type, field_ref);
if (is_putting)
{
@ -3484,7 +3485,8 @@ maybe_adjust_start_pc (struct JCF *jcf, int code_offset,
For method invocation, we modify the arguments so that a
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)
@ -3518,6 +3520,15 @@ force_evaluation_order (tree node)
/* This reverses the evaluation order. This is a desired effect. */
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 :
build2 (COMPOUND_EXPR, void_type_node, cmp, saved));

View file

@ -686,6 +686,9 @@ extern GTY(()) tree java_global_trees[JTI_MAX];
#define wfl_operator \
java_global_trees[JTI_WFL_OPERATOR]
/* The decl for "_Jv_ResolvePoolEntry". */
extern GTY(()) tree soft_resolvepoolentry_node;
extern const char *cyclic_inheritance_report;
struct lang_identifier GTY(())
@ -1285,6 +1288,7 @@ extern tree get_method_index (tree decl);
extern void make_class_data (tree);
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);
extern void lang_init_source (int);