diff options
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 |