summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--gcc/java/ChangeLog22
-rw-r--r--gcc/java/builtins.c10
-rw-r--r--gcc/java/class.c115
-rw-r--r--gcc/java/constants.c72
-rw-r--r--gcc/java/decl.c11
-rw-r--r--gcc/java/expr.c15
-rw-r--r--gcc/java/java-tree.h4
7 files changed, 185 insertions, 64 deletions
diff --git a/gcc/java/ChangeLog b/gcc/java/ChangeLog
index 89ec5688573..deaaa3132ce 100644
--- a/gcc/java/ChangeLog
+++ b/gcc/java/ChangeLog
@@ -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
diff --git a/gcc/java/builtins.c b/gcc/java/builtins.c
index f4a8efb2a1b..dcfff1c1ef5 100644
--- a/gcc/java/builtins.c
+++ b/gcc/java/builtins.c
@@ -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 ();
}
diff --git a/gcc/java/class.c b/gcc/java/class.c
index 54e310d0d3a..321c1e49554 100644
--- a/gcc/java/class.c
+++ b/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);
-
- 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));
- }
+ /* 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;
}
int
diff --git a/gcc/java/constants.c b/gcc/java/constants.c
index a5d9622bdab..ff58b87852d 100644
--- a/gcc/java/constants.c
+++ b/gcc/java/constants.c
@@ -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));
diff --git a/gcc/java/decl.c b/gcc/java/decl.c
index 2feac350417..204a674b175 100644
--- a/gcc/java/decl.c
+++ b/gcc/java/decl.c
@@ -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);
diff --git a/gcc/java/expr.c b/gcc/java/expr.c
index ae1055ed268..3cc33aed68d 100644
--- a/gcc/java/expr.c
+++ b/gcc/java/expr.c
@@ -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));
diff --git a/gcc/java/java-tree.h b/gcc/java/java-tree.h
index 036fb83cea0..a55e9ab476b 100644
--- a/gcc/java/java-tree.h
+++ b/gcc/java/java-tree.h
@@ -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);