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:
parent
a68b179c86
commit
2c80f01549
7 changed files with 183 additions and 62 deletions
|
@ -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
|
||||
|
|
|
@ -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 ();
|
||||
}
|
||||
|
||||
|
|
111
gcc/java/class.c
111
gcc/java/class.c
|
@ -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
|
||||
|
|
|
@ -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));
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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));
|
||||
|
|
|
@ -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);
|
||||
|
|
Loading…
Add table
Reference in a new issue