OSDN Git Service

* typeck.c (find_method_in_interfaces): Update.
[pf3gnuchains/gcc-fork.git] / gcc / java / class.c
index a22a936..82b71b4 100644 (file)
@@ -6,7 +6,7 @@ This file is part of GCC.
 
 GCC is free software; you can redistribute it and/or modify
 it under the terms of the GNU General Public License as published by
-the Free Software Foundation; either version 2, or (at your option)
+the Free Software Foundation; either version 3, or (at your option)
 any later version.
 
 GCC is distributed in the hope that it will be useful,
@@ -15,9 +15,8 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 GNU General Public License for more details.
 
 You should have received a copy of the GNU General Public License
-along with GCC; see the file COPYING.  If not, write to
-the Free Software Foundation, 51 Franklin Street, Fifth Floor,
-Boston, MA 02110-1301, USA.
+along with GCC; see the file COPYING3.  If not see
+<http://www.gnu.org/licenses/>.
 
 Java and all Java-based marks are trademarks or registered trademarks
 of Sun Microsystems, Inc. in the United States and other countries.
@@ -110,6 +109,10 @@ static GTY(()) tree class_roots[4];
 
 static GTY(()) VEC(tree,gc) *registered_class;
 
+/* A tree that returns the address of the class$ of the class
+   currently being compiled.  */
+static GTY(()) tree this_classdollar;
+
 /* Return the node that most closely represents the class whose name
    is IDENT.  Start the search from NODE (followed by its siblings).
    Return NULL if an appropriate node does not exist.  */
@@ -424,8 +427,7 @@ push_class (tree class_type, tree class_name)
   tree decl, signature;
   location_t saved_loc = input_location;
 #ifndef USE_MAPPED_LOCATION
-  tree source_name = identifier_subst (class_name, "", '.', '/', ".java");
-  input_filename = IDENTIFIER_POINTER (source_name);
+  input_filename = "<unknown>";
   input_line = 0;
 #endif
   CLASS_P (class_type) = 1;
@@ -669,19 +671,6 @@ add_interface (tree this_class, tree interface_class)
   BINFO_BASE_APPEND (TYPE_BINFO (this_class), interface_binfo);
 }
 
-#if 0
-/* Return the address of a pointer to the first FUNCTION_DECL
-   in the list (*LIST) whose DECL_NAME is NAME. */
-
-static tree *
-find_named_method (tree *list, tree name)
-{
-  while (*list && DECL_NAME (*list) != name)
-    list = &TREE_CHAIN (*list);
-  return list;
-}
-#endif
-
 static tree
 build_java_method_type (tree fntype, tree this_class, int access_flags)
 {
@@ -700,6 +689,15 @@ build_java_method_type (tree fntype, tree this_class, int access_flags)
   return fntype;
 }
 
+static void
+hide (tree decl ATTRIBUTE_UNUSED)
+{
+#ifdef HAVE_GAS_HIDDEN
+  DECL_VISIBILITY (decl) = VISIBILITY_HIDDEN;
+  DECL_VISIBILITY_SPECIFIED (decl) = 1;
+#endif
+}
+
 tree
 add_method_1 (tree this_class, int access_flags, tree name, tree function_type)
 {
@@ -728,6 +726,14 @@ add_method_1 (tree this_class, int access_flags, tree name, tree function_type)
   TREE_CHAIN (fndecl) = TYPE_METHODS (this_class);
   TYPE_METHODS (this_class) = fndecl;
 
+  /* If pointers to member functions use the least significant bit to
+     indicate whether a function is virtual, ensure a pointer
+     to this function will have that bit clear.  */
+  if (TARGET_PTRMEMFUNC_VBIT_LOCATION == ptrmemfunc_vbit_in_pfn
+      && !(access_flags & ACC_STATIC)
+      && DECL_ALIGN (fndecl) < 2 * BITS_PER_UNIT)
+    DECL_ALIGN (fndecl) = 2 * BITS_PER_UNIT;
+
   /* Notice that this is a finalizer and update the class type
      accordingly. This is used to optimize instance allocation. */
   if (name == finalize_identifier_node
@@ -744,6 +750,10 @@ add_method_1 (tree this_class, int access_flags, tree name, tree function_type)
       METHOD_NATIVE (fndecl) = 1;
       DECL_EXTERNAL (fndecl) = 1;
     }
+  else
+    /* FNDECL is external unless we are compiling it into this object
+       file.  */
+    DECL_EXTERNAL (fndecl) = CLASS_FROM_CURRENTLY_COMPILED_P (this_class) == 0;
   if (access_flags & ACC_STATIC) 
     METHOD_STATIC (fndecl) = DECL_INLINE (fndecl) = 1;
   if (access_flags & ACC_FINAL) 
@@ -806,6 +816,10 @@ add_field (tree class, tree name, tree field_type, int flags)
       /* Always make field externally visible.  This is required so
         that native methods can always access the field.  */
       TREE_PUBLIC (field) = 1;
+      /* Hide everything that shouldn't be visible outside a DSO.  */
+      if (flag_indirect_classes
+         || (FIELD_PRIVATE (field)))
+       hide (field);
       /* Considered external unless we are compiling it into this
         object file.  */
       DECL_EXTERNAL (field) = (is_compiled_class (class) != 2);
@@ -837,29 +851,9 @@ set_constant_value (tree field, tree constant)
                && TREE_TYPE (field) == string_ptr_type_node))
        error ("ConstantValue attribute of field '%s' has wrong type",
               IDENTIFIER_POINTER (DECL_NAME (field)));
-      if (FIELD_FINAL (field))
-       DECL_FIELD_FINAL_IUD (field) = 1;
     }
 }
 
-/* Count the number of Unicode chars encoded in a given Ut8 string. */
-
-#if 0
-int
-strLengthUtf8 (char *str, int len)
-{
-  register unsigned char* ptr = (unsigned char*) str;
-  register unsigned char *limit = ptr + len;
-  int str_length = 0;
-  for (; ptr < limit; str_length++) {
-    if (UTF8_GET (ptr, limit) < 0)
-      return -1;
-  }
-  return str_length;
-}
-#endif
-
-
 /* Calculate a hash value for a string encoded in Utf8 format.
  * This returns the same hash value as specified for java.lang.String.hashCode.
  */
@@ -981,7 +975,11 @@ build_static_class_ref (tree type)
       decl = build_decl (VAR_DECL, decl_name, class_type_node);
       TREE_STATIC (decl) = 1;
       if (! flag_indirect_classes)
-       TREE_PUBLIC (decl) = 1;
+       {
+         TREE_PUBLIC (decl) = 1;
+         if (CLASS_PRIVATE (TYPE_NAME (type)))
+           hide (decl);
+       }
       DECL_IGNORED_P (decl) = 1;
       DECL_ARTIFICIAL (decl) = 1;
       if (is_compiled_class (type) == 1)
@@ -1020,6 +1018,7 @@ build_classdollar_field (tree type)
       TREE_CONSTANT (decl) = 1;
       TREE_READONLY (decl) = 1;
       TREE_PUBLIC (decl) = 1;
+      hide (decl);
       DECL_IGNORED_P (decl) = 1;
       DECL_ARTIFICIAL (decl) = 1;
       MAYBE_CREATE_VAR_LANG_DECL_SPECIFIC (decl);
@@ -1031,6 +1030,52 @@ build_classdollar_field (tree type)
   return decl;
 }
 
+/* Create a local variable that holds the current class$.  */
+
+void
+cache_this_class_ref (tree fndecl)
+{
+  if (optimize)
+    {
+      tree classdollar_field;
+      if (flag_indirect_classes)
+       classdollar_field = build_classdollar_field (output_class);
+      else
+       classdollar_field = build_static_class_ref (output_class);
+
+      this_classdollar = build_decl (VAR_DECL, NULL_TREE, 
+                                    TREE_TYPE (classdollar_field));
+      
+      java_add_local_var (this_classdollar);
+      java_add_stmt (build2 (MODIFY_EXPR, TREE_TYPE (this_classdollar), 
+                            this_classdollar, classdollar_field));
+    }
+  else
+    this_classdollar = build_classdollar_field (output_class);
+
+  /* Prepend class initialization for static methods reachable from
+     other classes.  */
+  if (METHOD_STATIC (fndecl)
+      && (! METHOD_PRIVATE (fndecl)
+          || INNER_CLASS_P (DECL_CONTEXT (fndecl)))
+      && ! DECL_CLINIT_P (fndecl)
+      && ! CLASS_INTERFACE (TYPE_NAME (DECL_CONTEXT (fndecl))))
+    {
+      tree init = build_call_expr (soft_initclass_node, 1,
+                                  this_classdollar);
+      java_add_stmt (init);
+    }
+}
+
+/* Remove the reference to the local variable that holds the current
+   class$.  */
+
+void
+uncache_this_class_ref (tree fndecl ATTRIBUTE_UNUSED)
+{
+  this_classdollar = build_classdollar_field (output_class);
+}
+
 /* Build a reference to the class TYPE.
    Also handles primitive types and array types. */
 
@@ -1050,7 +1095,7 @@ build_class_ref (tree type)
        return build_indirect_class_ref (type);
 
       if (type == output_class && flag_indirect_classes)
-       return build_classdollar_field (type);
+       return this_classdollar;
       
       if (TREE_CODE (type) == RECORD_TYPE)
        return build_static_class_ref (type);
@@ -1116,13 +1161,12 @@ build_static_field_ref (tree fdecl)
 {
   tree fclass = DECL_CONTEXT (fdecl);
   int is_compiled = is_compiled_class (fclass);
-  int from_class = ! CLASS_FROM_SOURCE_P (current_class);
 
   /* Allow static final fields to fold to a constant.  When using
      -findirect-dispatch, we simply never do this folding if compiling
      from .class; in the .class file constants will be referred to via
      the constant pool.  */
-  if ((!flag_indirect_dispatch || !from_class)
+  if (!flag_indirect_dispatch
       && (is_compiled
          || (FIELD_FINAL (fdecl) && DECL_INITIAL (fdecl) != NULL_TREE
              && (JSTRING_TYPE_P (TREE_TYPE (fdecl))
@@ -1152,20 +1196,16 @@ build_static_field_ref (tree fdecl)
 
       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 test
+        = build_call_expr (built_in_decls[BUILT_IN_EXPECT], 2,
+                          build2 (EQ_EXPR, boolean_type_node,
+                                  cache_entry, null_pointer_node),
+                          boolean_false_node);
       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);
+       = build_call_expr (soft_resolvepoolentry_node, 2,
+                          build_class_ref (output_class),
+                          cpool_index_cst);
       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);
@@ -1635,8 +1675,7 @@ make_class_data (tree type)
   tree id_class = get_identifier("java.lang.Class");
   /** Offset from start of virtual function table declaration
       to where objects actually point at, following new g++ ABI. */
-  tree dtable_start_offset = build_int_cst (NULL_TREE,
-                                           2 * POINTER_SIZE / BITS_PER_UNIT);
+  tree dtable_start_offset = size_int (2 * POINTER_SIZE / BITS_PER_UNIT);
   VEC(int, heap) *field_indexes;
   tree first_real_field;
 
@@ -1665,6 +1704,10 @@ make_class_data (tree type)
 
       TREE_PUBLIC (dtable_decl) = 1;
       DECL_INITIAL (dtable_decl) = dtable;
+      /* The only dispatch table exported from a DSO is the dispatch
+        table for java.lang.Class.  */
+      if (DECL_NAME (type_decl) != id_class)
+       hide (dtable_decl);
       if (! flag_indirect_classes)
        rest_of_decl_compilation (dtable_decl, 1, 0);
       /* Maybe we're compiling Class as the first class.  If so, set
@@ -1698,7 +1741,7 @@ make_class_data (tree type)
   /* gcj sorts fields so that static fields come first, followed by
      instance fields.  Unfortunately, by the time this takes place we
      have already generated the reflection_data for this class, and
-     that data contians indexes into the fields.  So, we generate a
+     that data contains indexes into the fields.  So, we generate a
      permutation that maps each original field index to its final
      position.  Then we pass this permutation to
      rewrite_reflection_indexes(), which fixes up the reflection
@@ -1807,8 +1850,7 @@ make_class_data (tree type)
           || DECL_CLINIT_P (method)
           || DECL_NAME (type_decl) == id_class
           || DECL_NAME (method) == id_main
-          || (METHOD_PUBLIC (method) && !METHOD_STATIC (method))
-          || TYPE_DOT_CLASS (type) == method)
+          || (METHOD_PUBLIC (method) && !METHOD_STATIC (method)))
         {
           init = make_method_value (method);
           method_count++;
@@ -1919,7 +1961,7 @@ make_class_data (tree type)
   PUSH_FIELD_VALUE (temp, "vtable",
                    (flag_indirect_classes 
                     ? null_pointer_node
-                    : build2 (PLUS_EXPR, dtable_ptr_type,
+                    : build2 (POINTER_PLUS_EXPR, dtable_ptr_type,
                               build1 (ADDR_EXPR, dtable_ptr_type,
                                       class_dtable_decl),
                               dtable_start_offset)));
@@ -1967,7 +2009,7 @@ make_class_data (tree type)
   else
     PUSH_FIELD_VALUE (cons, "vtable",
                      dtable_decl == NULL_TREE ? null_pointer_node
-                     : build2 (PLUS_EXPR, dtable_ptr_type,
+                     : build2 (POINTER_PLUS_EXPR, dtable_ptr_type,
                                build1 (ADDR_EXPR, dtable_ptr_type,
                                        dtable_decl),
                                dtable_start_offset));
@@ -2127,17 +2169,6 @@ make_class_data (tree type)
 void
 finish_class (void)
 {
-  if (TYPE_VERIFY_METHOD (output_class))
-    {
-      tree verify_method = TYPE_VERIFY_METHOD (output_class);
-      DECL_SAVED_TREE (verify_method) 
-       = add_stmt_to_compound (DECL_SAVED_TREE (verify_method), void_type_node,
-                               build1 (RETURN_EXPR, void_type_node, NULL));
-      java_genericize (verify_method);
-      cgraph_finalize_function (verify_method, false);
-      TYPE_ASSERTIONS (current_class) = NULL;
-    }
-
   java_expand_catch_classes (current_class);
 
   current_function_decl = NULL_TREE;
@@ -2161,10 +2192,6 @@ is_compiled_class (tree class)
     return 1;
   if (TYPE_ARRAY_P (class))
     return 0;
-  /* We have to check this explicitly to avoid trying to load a class
-     that we're currently parsing.  */
-  if (class == current_class)
-    return 2;
 
   seen_in_zip = (TYPE_JCF (class) && JCF_SEEN_IN_ZIP (TYPE_JCF (class)));
   if (CLASS_FROM_CURRENTLY_COMPILED_P (class))
@@ -2174,7 +2201,7 @@ is_compiled_class (tree class)
         been loaded already. Load it if necessary. This prevent
         build_class_ref () from crashing. */
 
-      if (seen_in_zip && !CLASS_LOADED_P (class))
+      if (seen_in_zip && !CLASS_LOADED_P (class) && (class != current_class))
         load_class (class, 1);
 
       /* We return 2 for class seen in ZIP and class from files
@@ -2186,9 +2213,7 @@ is_compiled_class (tree class)
     {
       if (!CLASS_LOADED_P (class))
        {
-         if (CLASS_FROM_SOURCE_P (class))
-           safe_layout_class (class);
-         else
+         if (class != current_class)
            load_class (class, 1);
        }
       return 1;
@@ -2285,8 +2310,6 @@ maybe_layout_super_class (tree super_class, tree this_class ATTRIBUTE_UNUSED)
     return NULL_TREE;
   else if (TREE_CODE (super_class) == RECORD_TYPE)
     {
-      if (!CLASS_LOADED_P (super_class) && CLASS_FROM_SOURCE_P (super_class))
-       safe_layout_class (super_class);
       if (!CLASS_LOADED_P (super_class))
        load_class (super_class, 1);
     }
@@ -2297,36 +2320,7 @@ maybe_layout_super_class (tree super_class, tree this_class ATTRIBUTE_UNUSED)
       if (TREE_TYPE (super_class) != NULL_TREE)
        super_class = TREE_TYPE (super_class);
       else
-       {
-#if 0
-         /* do_resolve_class expects an EXPR_WITH_FILE_LOCATION, so
-            we give it one.  */
-         tree this_wrap = NULL_TREE;
-
-         /* Set the correct context for class resolution.  */
-         current_class = this_class;
-
-         if (this_class)
-           {
-             tree this_decl = TYPE_NAME (this_class);
-#ifdef USE_MAPPED_LOCATION
-             this_wrap = build_expr_wfl (this_class,
-                                         DECL_SOURCE_LOCATION (this_decl));
-#else
-             this_wrap = build_expr_wfl (this_class,
-                                         DECL_SOURCE_FILE (this_decl),
-                                         DECL_SOURCE_LINE (this_decl), 0);
-#endif
-           }
-         super_class
-           = do_resolve_class (DECL_CONTEXT (TYPE_NAME (this_class)),
-                               this_class, super_class, NULL_TREE, this_wrap);
-         if (!super_class)
-           return NULL_TREE;   /* FIXME, NULL_TREE not checked by caller. */
-         super_class = TREE_TYPE (super_class);
-#endif
-         gcc_unreachable ();
-       }
+       gcc_unreachable ();
     }
   if (!TYPE_SIZE (super_class))
     safe_layout_class (super_class);
@@ -2353,6 +2347,7 @@ safe_layout_class (tree class)
 void
 layout_class (tree this_class)
 {
+  int i;
   tree super_class = CLASSTYPE_SUPER (this_class);
 
   class_list = tree_cons (this_class, NULL_TREE, class_list);
@@ -2403,28 +2398,22 @@ layout_class (tree this_class)
 
   layout_type (this_class);
 
-  /* Also recursively load/layout any superinterfaces, but only if
-     class was loaded from bytecode.  The source parser will take care
-     of this itself.  */
-  if (!CLASS_FROM_SOURCE_P (this_class))
+  /* Also recursively load/layout any superinterfaces.  */
+  if (TYPE_BINFO (this_class))
     {
-      int i;
-            if (TYPE_BINFO (this_class))
+      for (i = BINFO_N_BASE_BINFOS (TYPE_BINFO (this_class)) - 1; i > 0; i--)
        {
-         for (i = BINFO_N_BASE_BINFOS (TYPE_BINFO (this_class)) - 1; i > 0; i--)
+         tree binfo = BINFO_BASE_BINFO (TYPE_BINFO (this_class), i);
+         tree super_interface = BINFO_TYPE (binfo);
+         tree maybe_super_interface 
+           = maybe_layout_super_class (super_interface, NULL_TREE);
+         if (maybe_super_interface == NULL
+             || TREE_CODE (TYPE_SIZE (maybe_super_interface)) == ERROR_MARK)
            {
-             tree binfo = BINFO_BASE_BINFO (TYPE_BINFO (this_class), i);
-             tree super_interface = BINFO_TYPE (binfo);
-             tree maybe_super_interface 
-               = maybe_layout_super_class (super_interface, NULL_TREE);
-             if (maybe_super_interface == NULL
-                 || TREE_CODE (TYPE_SIZE (maybe_super_interface)) == ERROR_MARK)
-               {
-                 TYPE_SIZE (this_class) = error_mark_node;
-                 CLASS_BEING_LAIDOUT (this_class) = 0;
-                 class_list = TREE_CHAIN (class_list);
-                 return;
-               }
+             TYPE_SIZE (this_class) = error_mark_node;
+             CLASS_BEING_LAIDOUT (this_class) = 0;
+             class_list = TREE_CHAIN (class_list);
+             return;
            }
        }
     }
@@ -2503,7 +2492,7 @@ layout_class_methods (tree this_class)
 
   if (TYPE_NVIRTUALS (this_class))
     return;
-
+  
   super_class = CLASSTYPE_SUPER (this_class);
 
   if (super_class)
@@ -2566,10 +2555,18 @@ layout_class_method (tree this_class, tree super_class,
   tree method_name = DECL_NAME (method_decl);
 
   TREE_PUBLIC (method_decl) = 1;
+
+  if (flag_indirect_classes
+      || (METHOD_PRIVATE (method_decl) && METHOD_STATIC (method_decl)
+         && ! METHOD_NATIVE (method_decl)
+         && ! special_method_p (method_decl)))
+    hide (method_decl);
+
   /* Considered external unless it is being compiled into this object
-     file.  */
-  DECL_EXTERNAL (method_decl) = ((is_compiled_class (this_class) != 2)
-                                || METHOD_NATIVE (method_decl));
+     file, or it was already flagged as external.  */
+  if (!DECL_EXTERNAL (method_decl))
+    DECL_EXTERNAL (method_decl) = ((is_compiled_class (this_class) != 2)
+                                   || METHOD_NATIVE (method_decl));
 
   if (ID_INIT_P (method_name))
     {
@@ -2611,7 +2608,6 @@ layout_class_method (tree this_class, tree super_class,
          set_method_index (method_decl, method_index);
          if (method_index == NULL_TREE 
              && ! flag_indirect_dispatch
-             && !CLASS_FROM_SOURCE_P (this_class)
              && ! DECL_ARTIFICIAL (super_method))
            error ("non-static method %q+D overrides static method",
                    method_decl);
@@ -2699,8 +2695,7 @@ emit_indirect_register_classes (tree *list_p)
   TREE_PUBLIC (t) = 1;
   DECL_EXTERNAL (t) = 1;
   register_class_fn = t;
-  t = tree_cons (NULL, reg_class_list, NULL);
-  t = build_function_call_expr (register_class_fn, t);
+  t = build_call_expr (register_class_fn, 1, reg_class_list);
   append_to_statement_list (t, list_p);
 }
 
@@ -2765,8 +2760,7 @@ emit_register_classes (tree *list_p)
       for (i = 0; VEC_iterate (tree, registered_class, i, klass); ++i)
        {
          t = build_fold_addr_expr (klass);
-         t = tree_cons (NULL, t, NULL);
-         t = build_function_call_expr (register_class_fn, t);
+         t = build_call_expr (register_class_fn, 1, t);
          append_to_statement_list (t, list_p);
        }
     }
@@ -2796,7 +2790,8 @@ build_symbol_entry (tree decl, tree special)
      system that this is a "special" symbol, i.e. one that should
      bypass access controls.  */
   if (special != NULL_TREE)
-    signature = build2 (PLUS_EXPR, TREE_TYPE (signature), signature, special);
+    signature = build2 (POINTER_PLUS_EXPR, TREE_TYPE (signature), signature,
+                       fold_convert (sizetype, special));
       
   START_RECORD_CONSTRUCTOR (sym, symbol_type);
   PUSH_FIELD_VALUE (sym, "clname", clname);
@@ -3027,15 +3022,17 @@ static int java_treetreehash_compare (const void *, const void *);
 static hashval_t
 java_treetreehash_hash (const void *k_p)
 {
-  struct treetreehash_entry *k = (struct treetreehash_entry *) k_p;
+  const struct treetreehash_entry *const k
+    = (const struct treetreehash_entry *) k_p;
   return JAVA_TREEHASHHASH_H (k->key);
 }
 
 static int
 java_treetreehash_compare (const void * k1_p, const void * k2_p)
 {
-  struct treetreehash_entry * k1 = (struct treetreehash_entry *) k1_p;
-  tree k2 = (tree) k2_p;
+  const struct treetreehash_entry *const k1
+    = (const struct treetreehash_entry *) k1_p;
+  const_tree const k2 = (const_tree) k2_p;
   return (k1->key == k2);
 }