From: Andrew Haley Date: Fri, 29 Apr 2005 18:43:25 +0000 (+0000) Subject: re PR java/19285 (Interfaces not initialized by static field access) X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=2c80f015490c820ec71549975d6276b41ed9ae4c;p=gcc.git re PR java/19285 (Interfaces not initialized by static field access) 2005-04-28 Andrew Haley 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 --- 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 + + 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 * 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);