aboutsummaryrefslogtreecommitdiff
path: root/gcc/java/class.c
diff options
context:
space:
mode:
authorAndrew Haley <aph@redhat.com>2005-04-29 18:43:25 +0000
committerAndrew Haley <aph@gcc.gnu.org>2005-04-29 18:43:25 +0000
commit2c80f015490c820ec71549975d6276b41ed9ae4c (patch)
tree158742ad984de1e20c807a73f81b51044ae5edee /gcc/java/class.c
parenta68b179c86764d41292502567a7b1252f4e57eae (diff)
downloadgcc-2c80f015490c820ec71549975d6276b41ed9ae4c.zip
gcc-2c80f015490c820ec71549975d6276b41ed9ae4c.tar.gz
gcc-2c80f015490c820ec71549975d6276b41ed9ae4c.tar.bz2
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
Diffstat (limited to 'gcc/java/class.c')
-rw-r--r--gcc/java/class.c115
1 files changed, 64 insertions, 51 deletions
diff --git a/gcc/java/class.c b/gcc/java/class.c
index 54e310d..321c1e4 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