diff options
author | Andrew Haley <aph@redhat.com> | 2005-04-29 18:43:25 +0000 |
---|---|---|
committer | Andrew Haley <aph@gcc.gnu.org> | 2005-04-29 18:43:25 +0000 |
commit | 2c80f015490c820ec71549975d6276b41ed9ae4c (patch) | |
tree | 158742ad984de1e20c807a73f81b51044ae5edee /gcc/java/class.c | |
parent | a68b179c86764d41292502567a7b1252f4e57eae (diff) | |
download | gcc-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.c | 115 |
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 |