OSDN Git Service

2006-02-20 Andrew Haley <aph@redhat.com>
[pf3gnuchains/gcc-fork.git] / gcc / java / jcf-parse.c
index bc733e8..b9d52b6 100644 (file)
@@ -1,5 +1,5 @@
 /* Parser for Java(TM) .class files.
-   Copyright (C) 1996, 1998, 1999, 2000, 2001, 2002, 2003, 2004
+   Copyright (C) 1996, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005
    Free Software Foundation, Inc.
 
 This file is part of GCC.
@@ -16,8 +16,8 @@ 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, 59 Temple Place - Suite 330,
-Boston, MA 02111-1307, USA.
+the Free Software Foundation, 51 Franklin Street, Fifth Floor,
+Boston, MA 02110-1301, USA.
 
 Java and all Java-based marks are trademarks or registered trademarks
 of Sun Microsystems, Inc. in the United States and other countries.
@@ -80,9 +80,12 @@ static GTY(()) tree parse_roots[3];
 /* The METHOD_DECL for the current method.  */
 #define current_method parse_roots[1]
 
-/* A list of file names.  */
+/* A list of TRANSLATION_UNIT_DECLs for the files to be compiled.  */
 #define current_file_list parse_roots[2]
 
+/* Line 0 in current file, if compiling from bytecode. */
+static location_t file_start_location;
+
 /* The Java archive that provides main_class;  the main input file. */
 static GTY(()) struct JCF * main_jcf;
 
@@ -95,7 +98,7 @@ static char *compute_class_name (struct ZipDirectory *zdir);
 static int classify_zip_file (struct ZipDirectory *zdir);
 static void parse_zip_file_entries (void);
 static void process_zip_dir (FILE *);
-static void parse_source_file_1 (tree, FILE *);
+static void parse_source_file_1 (tree, const char *, FILE *);
 static void parse_source_file_2 (void);
 static void parse_source_file_3 (void);
 static void parse_class_file (void);
@@ -117,7 +120,7 @@ handle_deprecated (void)
   else
     {
       /* Shouldn't happen.  */
-      abort ();
+      gcc_unreachable ();
     }
 }
 
@@ -128,21 +131,60 @@ set_source_filename (JCF *jcf, int index)
 {
   tree sfname_id = get_name_constant (jcf, index);
   const char *sfname = IDENTIFIER_POINTER (sfname_id);
-  if (input_filename != NULL)
+  const char *old_filename = input_filename;
+  int new_len = IDENTIFIER_LENGTH (sfname_id);
+  if (old_filename != NULL)
     {
-      int old_len = strlen (input_filename);
-      int new_len = IDENTIFIER_LENGTH (sfname_id);
+      int old_len = strlen (old_filename);
       /* Use the current input_filename (derived from the class name)
         if it has a directory prefix, but otherwise matches sfname. */
       if (old_len > new_len
-         && strcmp (sfname, input_filename + old_len - new_len) == 0
-         && (input_filename[old_len - new_len - 1] == '/'
-             || input_filename[old_len - new_len - 1] == '\\'))
-       return;
+         && strcmp (sfname, old_filename + old_len - new_len) == 0
+         && (old_filename[old_len - new_len - 1] == '/'
+             || old_filename[old_len - new_len - 1] == '\\'))
+       {
+#ifndef USE_MAPPED_LOCATION
+         DECL_SOURCE_LOCATION (TYPE_NAME (current_class)) = input_location;
+         file_start_location = input_location;
+#endif
+         return;
+       }
+    }
+  if (strchr (sfname, '/') == NULL && strchr (sfname, '\\') == NULL)
+    {
+      const char *class_name
+       = IDENTIFIER_POINTER (DECL_NAME (TYPE_NAME (current_class)));
+      char *dot = strrchr (class_name, '.');
+      if (dot != NULL)
+       {
+         /* Length of prefix, not counting final dot. */
+         int i = dot - class_name;
+         /* Concatenate current package prefix with new sfname. */
+         char *buf = XNEWVEC (char, i + new_len + 2); /* Space for '.' and '\0'. */
+         strcpy (buf + i + 1, sfname);
+         /* Copy package from class_name, replacing '.' by DIR_SEPARATOR.
+            Note we start at the end with the final package dot. */
+         for (; i >= 0;  i--)
+           {
+             char c = class_name[i];
+             if (c == '.')
+               c = DIR_SEPARATOR;
+             buf[i] = c;
+           }
+         sfname_id = get_identifier (buf);
+         free (buf);
+         sfname = IDENTIFIER_POINTER (sfname_id);
+       }
     }
+      
+#ifdef USE_MAPPED_LOCATION
+  line_table.maps[line_table.used-1].to_file = sfname;
+#else
   input_filename = sfname;
-  DECL_SOURCE_FILE (TYPE_NAME (current_class)) = sfname;
-  if (current_class == main_class) main_input_filename = input_filename;
+  DECL_SOURCE_LOCATION (TYPE_NAME (current_class)) = input_location;
+  file_start_location = input_location;
+#endif
+  if (current_class == main_class) main_input_filename = sfname;
 }
 
 #define HANDLE_SOURCEFILE(INDEX) set_source_filename (jcf, INDEX)
@@ -243,12 +285,12 @@ set_source_filename (JCF *jcf, int index)
 tree
 parse_signature (JCF *jcf, int sig_index)
 {
-  if (sig_index <= 0 || sig_index >= JPOOL_SIZE (jcf)
-      || JPOOL_TAG (jcf, sig_index) != CONSTANT_Utf8)
-    abort ();
-  else
-    return parse_signature_string (JPOOL_UTF_DATA (jcf, sig_index),
-                                  JPOOL_UTF_LENGTH (jcf, sig_index));
+  gcc_assert (sig_index > 0
+             && sig_index < JPOOL_SIZE (jcf)
+             && JPOOL_TAG (jcf, sig_index) == CONSTANT_Utf8);
+
+  return parse_signature_string (JPOOL_UTF_DATA (jcf, sig_index),
+                                JPOOL_UTF_LENGTH (jcf, sig_index));
 }
 
 tree
@@ -353,10 +395,7 @@ tree
 get_name_constant (JCF *jcf, int index)
 {
   tree name = get_constant (jcf, index);
-
-  if (TREE_CODE (name) != IDENTIFIER_NODE)
-    abort ();
-
+  gcc_assert (TREE_CODE (name) == IDENTIFIER_NODE);
   return name;
 }
 
@@ -403,24 +442,40 @@ handle_innerclass_attribute (int count, JCF *jcf)
 static tree
 give_name_to_class (JCF *jcf, int i)
 {
-  if (i <= 0 || i >= JPOOL_SIZE (jcf)
-      || JPOOL_TAG (jcf, i) != CONSTANT_Class)
-    abort ();
-  else
+  gcc_assert (i > 0
+             && i < JPOOL_SIZE (jcf)
+             && JPOOL_TAG (jcf, i) == CONSTANT_Class);
+
     {
+      tree package_name = NULL_TREE, tmp;
       tree this_class;
       int j = JPOOL_USHORT1 (jcf, i);
       /* verify_constant_pool confirmed that j is a CONSTANT_Utf8. */
       tree class_name = unmangle_classname ((const char *) JPOOL_UTF_DATA (jcf, j),
                                            JPOOL_UTF_LENGTH (jcf, j));
       this_class = lookup_class (class_name);
-      input_filename = DECL_SOURCE_FILE (TYPE_NAME (this_class));
-      input_line = 0;
+#ifdef USE_MAPPED_LOCATION
+      {
+      tree source_name = identifier_subst (class_name, "", '.', '/', ".java");
+      const char *sfname = IDENTIFIER_POINTER (source_name);
+      linemap_add (&line_table, LC_ENTER, false, sfname, 0);
+      input_location = linemap_line_start (&line_table, 0, 1);
+      file_start_location = input_location;
+      DECL_SOURCE_LOCATION (TYPE_NAME (this_class)) = input_location;
+      if (main_input_filename == NULL && jcf == main_jcf)
+       main_input_filename = sfname;
+      }
+#else
+      input_location = DECL_SOURCE_LOCATION (TYPE_NAME (this_class));
       if (main_input_filename == NULL && jcf == main_jcf)
        main_input_filename = input_filename;
+#endif
 
       jcf->cpool.data[i].t = this_class;
       JPOOL_TAG (jcf, i) = CONSTANT_ResolvedClass;
+      split_qualified_name (&package_name, &tmp, 
+                           DECL_NAME (TYPE_NAME (this_class)));
+      TYPE_PACKAGE (this_class) = package_name;
       return this_class;
     }
 }
@@ -431,9 +486,9 @@ tree
 get_class_constant (JCF *jcf, int i)
 {
   tree type;
-  if (i <= 0 || i >= JPOOL_SIZE (jcf)
-      || (JPOOL_TAG (jcf, i) & ~CONSTANT_ResolvedFlag) != CONSTANT_Class)
-    abort ();
+  gcc_assert (i > 0
+             && i < JPOOL_SIZE (jcf)
+             && (JPOOL_TAG (jcf, i) & ~CONSTANT_ResolvedFlag) == CONSTANT_Class);
 
   if (JPOOL_TAG (jcf, i) != CONSTANT_ResolvedClass)
     {
@@ -482,11 +537,17 @@ read_class (tree name)
 
   if (jcf == NULL)
     {
+      const char* path_name;
       this_jcf.zipd = NULL;
       jcf = &this_jcf;
-      if (find_class (IDENTIFIER_POINTER (name), IDENTIFIER_LENGTH (name),
-                     &this_jcf, 1) == 0)
+      
+      path_name = find_class (IDENTIFIER_POINTER (name),
+                             IDENTIFIER_LENGTH (name),
+                             &this_jcf, 1);
+      if (path_name == 0)
        return 0;
+      else
+       free((char *) path_name);
     }
 
   current_jcf = jcf;
@@ -494,6 +555,7 @@ read_class (tree name)
   if (current_jcf->java_source)
     {
       const char *filename = current_jcf->filename;
+      char *real_path;
       tree given_file, real_file;
       FILE *finput;
       int generate;
@@ -502,27 +564,29 @@ read_class (tree name)
       java_push_parser_context ();
 
       given_file = get_identifier (filename);
-      real_file = get_identifier (lrealpath (filename));
+      filename = IDENTIFIER_POINTER (given_file);
+      real_path = lrealpath (filename);
+      real_file = get_identifier (real_path);
+      free (real_path);
 
       generate = IS_A_COMMAND_LINE_FILENAME_P (given_file);
-      if (wfl_operator == NULL_TREE)
-       wfl_operator = build_expr_wfl (NULL_TREE, NULL, 0, 0);
-      EXPR_WFL_FILENAME_NODE (wfl_operator) = given_file;
-      input_filename = ggc_strdup (filename);
       output_class = current_class = NULL_TREE;
       current_function_decl = NULL_TREE;
 
       if (! HAS_BEEN_ALREADY_PARSED_P (real_file))
        {
-         if (! (finput = fopen (input_filename, "r")))
-           fatal_error ("can't reopen %s: %m", input_filename);
+         if (! (finput = fopen (filename, "r")))
+           fatal_error ("can't reopen %s: %m", filename);
 
-         parse_source_file_1 (real_file, finput);
+         parse_source_file_1 (real_file, filename, finput);
          parse_source_file_2 ();
          parse_source_file_3 ();
 
          if (fclose (finput))
            fatal_error ("can't close %s: %m", input_filename);
+#ifdef USE_MAPPED_LOCATION
+         linemap_add (&line_table, LC_LEAVE, false, NULL, 0);
+#endif
        }
       JCF_FINISH (current_jcf);
       java_pop_parser_context (generate);
@@ -535,7 +599,7 @@ read_class (tree name)
          java_parser_context_save_global ();
          java_push_parser_context ();
          output_class = current_class = class;
-         input_filename = current_jcf->filename;
+         ctxp->save_location = input_location;
          if (JCF_SEEN_IN_ZIP (current_jcf))
            read_zip_member(current_jcf,
                            current_jcf->zipd, current_jcf->zipd->zipf);
@@ -566,7 +630,14 @@ void
 load_class (tree class_or_name, int verbose)
 {
   tree name, saved;
-  int class_loaded;
+  int class_loaded = 0;
+  tree class_decl = NULL_TREE;
+  bool is_compiled_class = false;
+
+  /* We've already failed, don't try again.  */
+  if (TREE_CODE (class_or_name) == RECORD_TYPE
+      && TYPE_DUMMY (class_or_name))
+    return;
 
   /* class_or_name can be the name of the class we want to load */
   if (TREE_CODE (class_or_name) == IDENTIFIER_NODE)
@@ -577,38 +648,95 @@ load_class (tree class_or_name, int verbose)
     name = TYPE_NAME (TREE_PURPOSE (class_or_name));
   /* Or it's a type in the making */
   else
+    name = DECL_NAME (TYPE_NAME (class_or_name));
+
+  class_decl = IDENTIFIER_CLASS_VALUE (name);
+  if (class_decl != NULL_TREE)
     {
-      /* If the class is from source code, then it must already be loaded.  */
-      if (CLASS_FROM_SOURCE_P (class_or_name))
-        return;
-      name = DECL_NAME (TYPE_NAME (class_or_name));
+      tree type = TREE_TYPE (class_decl);
+      is_compiled_class
+       = ((TYPE_JCF (type) && JCF_SEEN_IN_ZIP (TYPE_JCF (type)))
+          || CLASS_FROM_CURRENTLY_COMPILED_P (type));
     }
 
+  /* If the class is from source code, then it must already be loaded.  */
+  class_decl = IDENTIFIER_CLASS_VALUE (name);
+  if (class_decl && CLASS_FROM_SOURCE_P (TREE_TYPE (class_decl)))
+    return;
+
   saved = name;
-  while (1)
+  
+  /* If flag_verify_invocations is unset, we don't try to load a class
+     unless we're looking for Object (which is fixed by the ABI) or
+     it's a class that we're going to compile.  */
+  if (flag_verify_invocations
+      || class_or_name == object_type_node
+      || is_compiled_class
+      || TREE_CODE (class_or_name) == IDENTIFIER_NODE)
     {
-      char *separator;
+      while (1)
+       {
+         char *separator;
 
-      if ((class_loaded = read_class (name)))
-       break;
+         /* We've already loaded it.  */
+         if (IDENTIFIER_CLASS_VALUE (name) != NULL_TREE)
+           {
+             tree tmp_decl = IDENTIFIER_CLASS_VALUE (name);
+             if (CLASS_PARSED_P (TREE_TYPE (tmp_decl)))
+               break;
+           }
+       
+         if (read_class (name))
+           break;
+
+         /* We failed loading name. Now consider that we might be looking
+            for an inner class.  */
+         if ((separator = strrchr (IDENTIFIER_POINTER (name), '$'))
+             || (separator = strrchr (IDENTIFIER_POINTER (name), '.')))
+           {
+             int c = *separator;
+             *separator = '\0';
+             name = get_identifier (IDENTIFIER_POINTER (name));
+             *separator = c;
+           }
+         /* Otherwise, we failed, we bail. */
+         else
+           break;
+       }
 
-      /* We failed loading name. Now consider that we might be looking
-        for a inner class. */
-      if ((separator = strrchr (IDENTIFIER_POINTER (name), '$'))
-         || (separator = strrchr (IDENTIFIER_POINTER (name), '.')))
+      {
+       /* have we found the class we're looking for?  */
+       tree type_decl = IDENTIFIER_CLASS_VALUE (saved);
+       tree type = type_decl ? TREE_TYPE (type_decl) : NULL;
+       class_loaded = type && CLASS_PARSED_P (type);
+      }              
+    }
+  
+  if (!class_loaded)
+    {
+      if (flag_verify_invocations || ! flag_indirect_dispatch
+         || flag_emit_class_files)
        {
-         int c = *separator;
-         *separator = '\0';
-         name = get_identifier (IDENTIFIER_POINTER (name));
-         *separator = c;
+         if (verbose)
+           error ("cannot find file for class %s", IDENTIFIER_POINTER (saved));
+       }
+      else if (verbose)
+       {
+         /* This is just a diagnostic during testing, not a real problem.  */
+         if (!quiet_flag)
+           warning (0, "cannot find file for class %s", 
+                    IDENTIFIER_POINTER (saved));
+         
+         /* Fake it.  */
+         if (TREE_CODE (class_or_name) == RECORD_TYPE)
+           {
+             set_super_info (0, class_or_name, object_type_node, 0);
+             TYPE_DUMMY (class_or_name) = 1;
+             /* We won't be able to output any debug info for this class.  */
+             DECL_IGNORED_P (TYPE_NAME (class_or_name)) = 1;
+           }
        }
-      /* Otherwise, we failed, we bail. */
-      else
-       break;
     }
-
-  if (!class_loaded && verbose)
-    error ("cannot find file for class %s", IDENTIFIER_POINTER (saved));
 }
 
 /* Parse the .class file JCF. */
@@ -662,6 +790,9 @@ jcf_parse (JCF* jcf)
   code = jcf_parse_final_attributes (jcf);
   if (code != 0)
     fatal_error ("error while parsing final attributes");
+#ifdef USE_MAPPED_LOCATION
+  linemap_add (&line_table, LC_LEAVE, false, NULL, 0);
+#endif
 
   /* The fields of class_type_node are already in correct order. */
   if (current_class != class_type_node && current_class != object_type_node)
@@ -675,7 +806,7 @@ jcf_parse (JCF* jcf)
         -fforce-classes-archive-check was specified. */
       if (!jcf->right_zip
          && (!flag_emit_class_files || flag_force_classes_archive_check))
-       fatal_error ("the `java.lang.Object' that was found in `%s' didn't have the special zero-length `gnu.gcj.gcj-compiled' attribute.  This generally means that your classpath is incorrectly set.  Use `info gcj \"Input Options\"' to see the info page describing how to set the classpath", jcf->filename);
+       fatal_error ("the %<java.lang.Object%> that was found in %qs didn't have the special zero-length %<gnu.gcj.gcj-compiled%> attribute.  This generally means that your classpath is incorrectly set.  Use %<info gcj \"Input Options\"%> to see the info page describing how to set the classpath", jcf->filename);
     }
   else
     all_class_list = tree_cons (NULL_TREE,
@@ -699,6 +830,20 @@ load_inner_classes (tree cur_class)
 }
 
 static void
+duplicate_class_warning (const char *filename)
+{
+  location_t warn_loc;
+#ifdef USE_MAPPED_LOCATION
+  linemap_add (&line_table, LC_RENAME, 0, filename, 0);
+  warn_loc = linemap_line_start (&line_table, 0, 1);
+#else
+  warn_loc.file = filename;
+  warn_loc.line = 0;
+#endif
+  warning (0, "%Hduplicate class will only be compiled once", &warn_loc);
+}
+
+static void
 parse_class_file (void)
 {
   tree method;
@@ -706,14 +851,10 @@ parse_class_file (void)
 
   java_layout_seen_class_methods ();
 
-  input_filename = DECL_SOURCE_FILE (TYPE_NAME (current_class));
-  input_line = 0;
+  input_location = DECL_SOURCE_LOCATION (TYPE_NAME (current_class));
+  file_start_location = input_location;
   (*debug_hooks->start_source_file) (input_line, input_filename);
 
-  /* Currently we always have to emit calls to _Jv_InitClass when
-     compiling from class files.  */
-  always_initialize_class_p = 1;
-
   gen_indirect_dispatch_tables (current_class);
 
   java_mark_class_local (current_class);
@@ -723,7 +864,7 @@ parse_class_file (void)
     {
       JCF *jcf = current_jcf;
 
-      if (METHOD_ABSTRACT (method))
+      if (METHOD_ABSTRACT (method) || METHOD_DUMMY (method))
        continue;
 
       if (METHOD_NATIVE (method))
@@ -757,10 +898,11 @@ parse_class_file (void)
          continue;
        }
 
-      input_line = 0;
+      input_location = DECL_SOURCE_LOCATION (TYPE_NAME (current_class));
       if (DECL_LINENUMBERS_OFFSET (method))
        {
          int i;
+         int min_line = 0;
          unsigned char *ptr;
          JCF_SEEK (jcf, DECL_LINENUMBERS_OFFSET (method));
          linenumber_count = i = JCF_readu2 (jcf);
@@ -771,9 +913,16 @@ parse_class_file (void)
              int line = GET_u2 (ptr);
              /* Set initial input_line to smallest linenumber.
               * Needs to be set before init_function_start. */
-             if (input_line == 0 || line < input_line)
-               input_line = line;
-           }  
+             if (min_line == 0 || line < min_line)
+               min_line = line;
+           }
+#ifdef USE_MAPPED_LOCATION
+         if (min_line != 0)
+           input_location = linemap_line_start (&line_table, min_line, 1);
+#else
+         if (min_line != 0)
+           input_line = min_line;
+#endif
        }
       else
        {
@@ -787,6 +936,21 @@ parse_class_file (void)
 
       give_name_to_locals (jcf);
 
+      /* Bump up start_label_pc_this_method so we get a unique label number
+        and reset highest_label_pc_this_method. */
+      if (highest_label_pc_this_method >= 0)
+       {
+         /* We adjust to the next multiple of 1000.  This is just a frill
+            so the last 3 digits of the label number match the bytecode
+            offset, which might make debugging marginally more convenient. */
+         start_label_pc_this_method
+           = ((((start_label_pc_this_method + highest_label_pc_this_method)
+                / 1000)
+               + 1)
+              * 1000);
+         highest_label_pc_this_method = -1;
+       }
+
       /* Convert bytecode to trees.  */
       expand_byte_code (jcf, method);
 
@@ -798,22 +962,20 @@ parse_class_file (void)
 
   finish_class ();
 
-  (*debug_hooks->end_source_file) (save_location.line);
+  (*debug_hooks->end_source_file) (LOCATION_LINE (save_location));
   input_location = save_location;
 }
 
 /* Parse a source file, as pointed by the current value of INPUT_FILENAME. */
 
 static void
-parse_source_file_1 (tree real_file, FILE *finput)
+parse_source_file_1 (tree real_file, const char *filename, FILE *finput)
 {
   int save_error_count = java_error_count;
 
   /* Mark the file as parsed.  */
   HAS_BEEN_ALREADY_PARSED_P (real_file) = 1;
 
-  jcf_dependency_add_file (input_filename, 0);
-
   lang_init_source (1);                    /* Error msgs have no method prototypes */
 
   /* There's no point in trying to find the current encoding unless we
@@ -827,6 +989,18 @@ parse_source_file_1 (tree real_file, FILE *finput)
   if (current_encoding == NULL || *current_encoding == '\0')
     current_encoding = DEFAULT_ENCODING;
 
+#ifdef USE_MAPPED_LOCATION
+  linemap_add (&line_table, LC_ENTER, false, filename, 0);
+  input_location = linemap_line_start (&line_table, 0, 125);
+#else
+  input_filename = filename;
+  input_line = 0;
+#endif
+  ctxp->file_start_location = input_location;
+  ctxp->filename = filename;
+
+  jcf_dependency_add_file (input_filename, 0);
+
   /* Initialize the parser */
   java_init_lex (finput, current_encoding);
   java_parse_abort_on_error ();
@@ -841,6 +1015,7 @@ static void
 parse_source_file_2 (void)
 {
   int save_error_count = java_error_count;
+  flag_verify_invocations = true;
   java_complete_class ();          /* Parse unsatisfied class decl. */
   java_parse_abort_on_error ();
 }
@@ -894,7 +1069,8 @@ void
 java_parse_file (int set_yydebug ATTRIBUTE_UNUSED)
 {
   int filename_count = 0;
-  char *list, *next;
+  location_t save_location = input_location;
+  char *file_list = NULL, *list, *next;
   tree node;
   FILE *finput = NULL;
   int in_quotes = 0;
@@ -902,10 +1078,10 @@ java_parse_file (int set_yydebug ATTRIBUTE_UNUSED)
   if (flag_filelist_file)
     {
       int avail = 2000;
-      finput = fopen (input_filename, "r");
+      finput = fopen (main_input_filename, "r");
       if (finput == NULL)
        fatal_error ("can't open %s: %m", input_filename);
-      list = xmalloc(avail);
+      list = XNEWVEC (char, avail);
       next = list;
       for (;;)
        {
@@ -932,9 +1108,10 @@ java_parse_file (int set_yydebug ATTRIBUTE_UNUSED)
        }
       fclose (finput);
       finput = NULL;
+      file_list = list;
     }
   else
-    list = input_filename ? xstrdup (input_filename) : 0;
+    list = (char *) main_input_filename;
 
   while (list)
     {
@@ -976,58 +1153,30 @@ java_parse_file (int set_yydebug ATTRIBUTE_UNUSED)
 
       if (list[0]) 
        {
-         char *value;
-         tree id;
-         int twice = 0;
-
-         int len = strlen (list);
-
-         obstack_grow0 (&temporary_obstack, list, len);
-         value = obstack_finish (&temporary_obstack);
+         node = get_identifier (list);
 
          filename_count++;
 
-         /* Exclude file that we see twice on the command line. For
-            all files except {Class,Error,Object,RuntimeException,String,
-            Throwable}.java we can rely on maybe_get_identifier. For
-            these files, we need to do a linear search of
-            current_file_list. This search happens only for these
-            files, presumably only when we're recompiling libgcj. */
+         /* Exclude file that we see twice on the command line. */
             
-         if ((id = maybe_get_identifier (value)))
-           {
-             if (predefined_filename_p (id))
-               {
-                 tree c;
-                 for (c = current_file_list; c; c = TREE_CHAIN (c))
-                   if (TREE_VALUE (c) == id)
-                     twice = 1;
-               }
-             else
-               twice = 1;
-           }
-
-         if (twice)
-           {
-             location_t warn_loc;
-             warn_loc.file = value;
-             warn_loc.line = 0;
-             warning ("%Hsource file seen twice on command line and "
-                      "will be compiled only once", &warn_loc);
-           }
+         if (IS_A_COMMAND_LINE_FILENAME_P (node))
+           duplicate_class_warning (IDENTIFIER_POINTER (node));
          else
            {
-             node = get_identifier (value);
+             tree file_decl = build_decl (TRANSLATION_UNIT_DECL, node, NULL);
+             TREE_CHAIN (file_decl) = current_file_list;
+             current_file_list = file_decl;
              IS_A_COMMAND_LINE_FILENAME_P (node) = 1;
-             current_file_list = tree_cons (NULL_TREE, node, 
-                                            current_file_list);
            }
        }
       list = next;
     }
 
+  if (file_list != NULL)
+    free (file_list);
+
   if (filename_count == 0)
-    warning ("no input file specified");
+    warning (0, "no input file specified");
 
   if (resource_name)
     {
@@ -1036,7 +1185,7 @@ java_parse_file (int set_yydebug ATTRIBUTE_UNUSED)
       /* Only one resource file may be compiled at a time.  */
       assert (TREE_CHAIN (current_file_list) == NULL);
 
-      resource_filename = IDENTIFIER_POINTER (TREE_VALUE (current_file_list));
+      resource_filename = IDENTIFIER_POINTER (DECL_NAME (current_file_list));
       compile_resource_file (resource_name, resource_filename);
 
       goto finish;
@@ -1047,28 +1196,31 @@ java_parse_file (int set_yydebug ATTRIBUTE_UNUSED)
   for (node = current_file_list; node; node = TREE_CHAIN (node))
     {
       unsigned char magic_string[4];
+      char *real_path;
       uint32 magic = 0;
-      tree name = TREE_VALUE (node);
+      tree name = DECL_NAME (node);
       tree real_file;
+      const char *filename = IDENTIFIER_POINTER (name);
 
       /* Skip already parsed files */
-      real_file = get_identifier (lrealpath (IDENTIFIER_POINTER (name)));
+      real_path = lrealpath (filename);
+      real_file = get_identifier (real_path);
+      free (real_path);
       if (HAS_BEEN_ALREADY_PARSED_P (real_file))
        continue;
-      
+
       /* Close previous descriptor, if any */
       if (finput && fclose (finput))
        fatal_error ("can't close input file %s: %m", main_input_filename);
       
-      finput = fopen (IDENTIFIER_POINTER (name), "rb");
+      finput = fopen (filename, "rb");
       if (finput == NULL)
-       fatal_error ("can't open %s: %m", IDENTIFIER_POINTER (name));
+       fatal_error ("can't open %s: %m", filename);
 
 #ifdef IO_BUFFER_SIZE
       setvbuf (finput, xmalloc (IO_BUFFER_SIZE),
               _IOFBF, IO_BUFFER_SIZE);
 #endif
-      input_filename = IDENTIFIER_POINTER (name);
 
       /* Figure what kind of file we're dealing with */
       if (fread (magic_string, 1, 4, finput) == 4)
@@ -1084,58 +1236,74 @@ java_parse_file (int set_yydebug ATTRIBUTE_UNUSED)
          current_jcf->read_state = finput;
          current_jcf->filbuf = jcf_filbuf_from_stdio;
          jcf_parse (current_jcf);
+         DECL_SOURCE_LOCATION (node) = file_start_location;
          TYPE_JCF (current_class) = current_jcf;
+         if (CLASS_FROM_CURRENTLY_COMPILED_P (current_class))
+           {
+             /* We've already compiled this class.  */
+             duplicate_class_warning (filename);
+             continue;
+           }
          CLASS_FROM_CURRENTLY_COMPILED_P (current_class) = 1;
-         TREE_PURPOSE (node) = current_class;
+         TREE_TYPE (node) = current_class;
        }
       else if (magic == (JCF_u4)ZIPMAGIC)
        {
-         ZIP_FILE_P (node) = 1;
          main_jcf = ggc_alloc (sizeof (JCF));
          JCF_ZERO (main_jcf);
          main_jcf->read_state = finput;
          main_jcf->filbuf = jcf_filbuf_from_stdio;
-         if (open_in_zip (main_jcf, input_filename, NULL, 0) <  0)
-           fatal_error ("bad zip/jar file %s", IDENTIFIER_POINTER (name));
+#ifdef USE_MAPPED_LOCATION
+         linemap_add (&line_table, LC_ENTER, false, filename, 0);
+         input_location = linemap_line_start (&line_table, 0, 1);
+#endif
+         if (open_in_zip (main_jcf, filename, NULL, 0) <  0)
+           fatal_error ("bad zip/jar file %s", filename);
          localToFile = SeenZipFiles;
          /* Register all the classes defined there.  */
          process_zip_dir (main_jcf->read_state);
+#ifdef USE_MAPPED_LOCATION
+         linemap_add (&line_table, LC_LEAVE, false, NULL, 0);
+#endif
          parse_zip_file_entries ();
-         /*
-         for (each entry)
-           CLASS_FROM_CURRENTLY_COMPILED_P (current_class) = 1;
-         */
        }
       else
        {
-         JAVA_FILE_P (node) = 1;
          java_push_parser_context ();
          java_parser_context_save_global ();
 
-         parse_source_file_1 (real_file, finput);
+         parse_source_file_1 (real_file, filename, finput);
          java_parser_context_restore_global ();
          java_pop_parser_context (1);
+#ifdef USE_MAPPED_LOCATION
+         linemap_add (&line_table, LC_LEAVE, false, NULL, 0);
+#endif
        }
     }
 
   for (ctxp = ctxp_for_generation;  ctxp;  ctxp = ctxp->next)
     {
-      input_filename = ctxp->filename;
+      input_location = ctxp->file_start_location;
       parse_source_file_2 ();
     }
 
   for (ctxp = ctxp_for_generation; ctxp; ctxp = ctxp->next)
     {
-      input_filename = ctxp->filename;
+      input_location = ctxp->file_start_location;
       parse_source_file_3 ();
     }
 
   for (node = current_file_list; node; node = TREE_CHAIN (node))
     {
-      input_filename = IDENTIFIER_POINTER (TREE_VALUE (node));
+      input_location = DECL_SOURCE_LOCATION (node);
       if (CLASS_FILE_P (node))
        {
-         output_class = current_class = TREE_PURPOSE (node);
+         /* FIXME: These two flags really should be independent.  We
+            should be able to compile fully binary compatible, but
+            with flag_verify_invocations on.  */
+         flag_verify_invocations = ! flag_indirect_dispatch;
+         output_class = current_class = TREE_TYPE (node);
+
          current_jcf = TYPE_JCF (current_class);
          layout_class (current_class);
          load_inner_classes (current_class);
@@ -1143,7 +1311,7 @@ java_parse_file (int set_yydebug ATTRIBUTE_UNUSED)
          JCF_FINISH (current_jcf);
        }
     }
-  input_filename = main_input_filename;
+  input_location = save_location;
 
   java_expand_classes ();
   if (java_report_errors () || flag_syntax_only)
@@ -1170,13 +1338,24 @@ compute_class_name (struct ZipDirectory *zdir)
 {
   char *class_name_in_zip_dir = ZIPDIR_FILENAME (zdir);
   char *class_name;
-  int j;
+  int i;
+  int filename_length = zdir->filename_length;
+
+  while (filename_length > 2 && strncmp (class_name_in_zip_dir, "./", 2) == 0)
+    {
+      class_name_in_zip_dir += 2;
+      filename_length -= 2;
+    }
+
+  filename_length -= strlen (".class");
+  class_name = XNEWVEC (char, filename_length + 1);
+  memcpy (class_name, class_name_in_zip_dir, filename_length);
+  class_name [filename_length] = '\0';
+
+  for (i = 0; i < filename_length; i++)
+    if (class_name[i] == '/')
+      class_name[i] = '.';
 
-  class_name = ALLOC (zdir->filename_length + 1 - 6);
-  strncpy (class_name, class_name_in_zip_dir, zdir->filename_length - 6);
-  class_name [zdir->filename_length - 6] = '\0';
-  for (j = 0; class_name[j]; ++j)
-    class_name[j] = class_name[j] == '/' ? '.' : class_name[j];
   return class_name;
 }
 
@@ -1230,6 +1409,32 @@ parse_zip_file_entries (void)
            current_jcf = TYPE_JCF (class);
            output_class = current_class = class;
 
+           if (CLASS_FROM_CURRENTLY_COMPILED_P (current_class))
+             {
+               /* We've already compiled this class.  */
+               duplicate_class_warning (current_jcf->filename);
+               break;
+             }
+           
+           CLASS_FROM_CURRENTLY_COMPILED_P (current_class) = 1;
+
+           /* This is a dummy class, and now we're compiling it for
+              real.  */
+           gcc_assert (! TYPE_DUMMY (class));
+
+           /* This is for a corner case where we have a superclass
+              but no superclass fields.  
+
+              This can happen if we earlier failed to lay out this
+              class because its superclass was still in the process
+              of being laid out; this occurs when we have recursive
+              class dependencies via inner classes.  Setting
+              TYPE_SIZE to null here causes CLASS_LOADED_P to return
+              false, so layout_class() will be called again.  */
+           if (TYPE_SIZE (class) && CLASSTYPE_SUPER (class)
+               && integer_zerop (TYPE_SIZE (class)))
+             TYPE_SIZE (class) = NULL_TREE;
+
            if (! CLASS_LOADED_P (class))
              {
                if (! CLASS_PARSED_P (class))
@@ -1243,9 +1448,8 @@ parse_zip_file_entries (void)
 
            if (TYPE_SIZE (current_class) != error_mark_node)
              {
-               input_filename = current_jcf->filename;
                parse_class_file ();
-               FREE (current_jcf->buffer); /* No longer necessary */
+               free (current_jcf->buffer); /* No longer necessary */
                /* Note: there is a way to free this buffer right after a
                   class seen in a zip file has been parsed. The idea is the
                   set its jcf in such a way that buffer will be reallocated
@@ -1258,11 +1462,11 @@ parse_zip_file_entries (void)
          {
            char *file_name, *class_name_in_zip_dir, *buffer;
            JCF *jcf;
-           file_name = ALLOC (zdir->filename_length + 1);
+           file_name = XNEWVEC (char, zdir->filename_length + 1);
            class_name_in_zip_dir = ZIPDIR_FILENAME (zdir);
            strncpy (file_name, class_name_in_zip_dir, zdir->filename_length);
            file_name[zdir->filename_length] = '\0';
-           jcf = ALLOC (sizeof (JCF));
+           jcf = XNEW (JCF);
            JCF_ZERO (jcf);
            jcf->read_state  = finput;
            jcf->filbuf      = jcf_filbuf_from_stdio;
@@ -1274,7 +1478,7 @@ parse_zip_file_entries (void)
            if (read_zip_member (jcf, zdir, localToFile) < 0)
              fatal_error ("error while reading %s from zip file", file_name);
 
-           buffer = ALLOC (zdir->filename_length + 1 +
+           buffer = XNEWVEC (char, zdir->filename_length + 1 +
                            (jcf->buffer_end - jcf->buffer));
            strcpy (buffer, file_name);
            /* This is not a typo: we overwrite the trailing \0 of the
@@ -1285,13 +1489,13 @@ parse_zip_file_entries (void)
            compile_resource_data (file_name, buffer,
                                   jcf->buffer_end - jcf->buffer);
            JCF_FINISH (jcf);
-           FREE (jcf);
-           FREE (buffer);
+           free (jcf);
+           free (buffer);
          }
          break;
 
        default:
-         abort ();
+         gcc_unreachable ();
        }
     }
 }
@@ -1319,7 +1523,7 @@ process_zip_dir (FILE *finput)
        continue;
 
       class_name = compute_class_name (zdir);
-      file_name  = ALLOC (zdir->filename_length+1);
+      file_name  = XNEWVEC (char, zdir->filename_length+1);
       jcf = ggc_alloc (sizeof (JCF));
       JCF_ZERO (jcf);