This is the mail archive of the cygwin-apps@cygwin.com mailing list for the Cygwin project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

gcj patches for cygwin gcc-3.1


cgf asked me to commit some patches to the cygwin gcc-3.1 branch. 

These java patches went into 3.1 after the cygwin branch, and increase
cygwin performance dramatically by caching the results of stat() calls.  


2002-06-09  David.Billinghurst <David.Billinghurst@riotinto.com>

        2002-05-18  Mark Mitchell  <mark@codesourcery.com>
        * java-tree.h (CLASS_BEING_LAIDOUT): Remove duplicate definition.
        * jcf-io.c (dirent.h): Include it.
        (fnmatch.h): Likewise.
        (compare_path): New function.
        (java_or_class_file): Likewise.
        (memoized_dirlist_entry): New type.
        (memoized_dirlist_lookup_eq): New function.
        (memoized_dirlists): New variable.
        (caching_stat): New function.
        (memoized_class_lookup_eq): New function.
        (memoized_class_lookups): Likewise.
        (find_class): Use memoized_class_lookups and caching_stat.
        * jcf.h (JCF_USE_SCANDIR): Define.
        * parse.y (java_expand_classes): Write the class files in reverse
        order.

        2002-05-13  Mark Mitchell  <mark@codesourcery.com>
        * jcf-write.c (write_classfile): Unlink the temporary file if it
        cannot be renamed.  Use concat to build up the name of the
        temporary file.

        2002-05-13  Mark Mitchell  <mark@codesourcery.com>
        * jcf-write.c (write_classfile): Unlink the temporary file if it
        cannot be renamed.  Use concat to build up the name of the
        temporary file.


Index: ChangeLog
===================================================================
RCS file: /cvs/gcc/gcc/gcc/java/ChangeLog,v
retrieving revision 1.925.2.54
diff -u -r1.925.2.54 ChangeLog
--- ChangeLog	15 May 2002 02:23:16 -0000	1.925.2.54
+++ ChangeLog	9 Jun 2002 02:16:04 -0000
@@ -1,3 +1,32 @@
+2002-06-07  David.Billinghurst <David.Billinghurst@riotinto.com>
+
+	2002-05-18  Mark Mitchell  <mark@codesourcery.com>
+	* java-tree.h (CLASS_BEING_LAIDOUT): Remove duplicate definition.
+	* jcf-io.c (dirent.h): Include it.
+	(fnmatch.h): Likewise.
+	(compare_path): New function.
+	(java_or_class_file): Likewise.
+	(memoized_dirlist_entry): New type.
+	(memoized_dirlist_lookup_eq): New function.
+	(memoized_dirlists): New variable.
+	(caching_stat): New function.
+	(memoized_class_lookup_eq): New function.
+	(memoized_class_lookups): Likewise.
+	(find_class): Use memoized_class_lookups and caching_stat.
+	* jcf.h (JCF_USE_SCANDIR): Define.
+	* parse.y (java_expand_classes): Write the class files in reverse
+	order.
+
+	2002-05-13  Mark Mitchell  <mark@codesourcery.com>
+	* jcf-write.c (write_classfile): Unlink the temporary file if it
+	cannot be renamed.  Use concat to build up the name of the
+	temporary file.
+
+	2002-05-13  Mark Mitchell  <mark@codesourcery.com>
+	* jcf-write.c (write_classfile): Unlink the temporary file if it
+	cannot be renamed.  Use concat to build up the name of the
+	temporary file.
+
 2002-05-14  Release Manager
 
 	* GCC 3.1 Released.
Index: java-tree.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/java/java-tree.h,v
retrieving revision 1.136.2.2
diff -u -r1.136.2.2 java-tree.h
--- java-tree.h	24 Apr 2002 22:16:08 -0000	1.136.2.2
+++ java-tree.h	9 Jun 2002 02:16:25 -0000
@@ -1424,11 +1424,6 @@
    layout of a class.  */
 #define CLASS_BEING_LAIDOUT(TYPE) TYPE_LANG_FLAG_6 (TYPE)
 
-/* True if class TYPE is currently being laid out. Helps in detection
-   of inheritance cycle occurring as a side effect of performing the
-   layout of a class.  */
-#define CLASS_BEING_LAIDOUT(TYPE) TYPE_LANG_FLAG_6 (TYPE)
-
 /* True if class TYPE has a field initializer finit$ function */
 #define CLASS_HAS_FINIT_P(TYPE) TYPE_FINIT_STMT_LIST (TYPE)
 
Index: jcf-io.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/java/jcf-io.c,v
retrieving revision 1.33
diff -u -r1.33 jcf-io.c
--- jcf-io.c	3 Dec 2001 19:13:40 -0000	1.33
+++ jcf-io.c	9 Jun 2002 02:16:32 -0000
@@ -1,5 +1,5 @@
 /* Utility routines for finding and reading Java(TM) .class files.
-   Copyright (C) 1996, 1997, 1998, 1999, 2000  Free Software Foundation, Inc.
+   Copyright (C) 1996, 1997, 1998, 1999, 2000, 2002  Free Software Foundation, Inc.
 
 This program is free software; you can redistribute it and/or modify
 it under the terms of the GNU General Public License as published by
@@ -29,6 +29,11 @@
 #include "tree.h"
 #include "toplev.h"
 #include "java-tree.h"
+#include "hashtab.h"
+#if JCF_USE_SCANDIR
+#include <dirent.h>
+#include <fnmatch.h>
+#endif
 
 #include "zlib.h"
 
@@ -304,10 +309,152 @@
 #endif
 }
 
+#if JCF_USE_SCANDIR
+
+/* A comparison function (as for qsort) that compares KEY (a char *
+   giving the basename of a file) with the name stored in ENTRY (a
+   dirent **).  */
+
+static int
+DEFUN(compare_path, (key, entry),
+      const void *key AND const void *entry)
+{
+  return strcmp ((const char *) key, 
+		 (*((const struct dirent **) entry))->d_name);
+}
+
+/* Returns nonzero if ENTRY names a .java or .class file.  */
+
+static int
+DEFUN(java_or_class_file, (entry),
+      const struct dirent *entry)
+{
+  const char *base = basename (entry->d_name);
+  return (fnmatch ("*.java", base, 0) == 0 || 
+	  fnmatch ("*.class", base, 0) == 0);
+}
+
+/* Information about the files present in a particular directory.  */
+typedef struct memoized_dirlist_entry 
+{
+  /* The name of the directory.  */
+  const char *dir;
+  /* The number of .java and .class files present, or -1 if we could
+     not, for some reason, obtain the list.  */
+  int num_files;
+  /* The .java and .class files in the directory, in alphabetical
+     order.  */
+  struct dirent **files;
+} memoized_dirlist_entry;
+
+/* Returns true if ENTRY (a memoized_dirlist_entry *) correponds to
+   the directory given by KEY (a char *) giving the directory 
+   name.  */
+
+static int
+DEFUN(memoized_dirlist_lookup_eq, (entry, key),
+      const void *entry AND const void *key)
+{
+  return strcmp ((const char *) key,
+		 ((const memoized_dirlist_entry *) entry)->dir) == 0;
+}
+
+/* A hash table mapping directory names to the lists of .java and
+   .class files in that directory.  */
+
+static htab_t memoized_dirlists;
+
+#endif
+
+/* Like stat, but avoids actually making the stat system call if we
+   know that it cannot succeed.  FILENAME and BUF are as for stat.  */
+
+static int
+DEFUN(caching_stat, (filename, buf),
+      char *filename AND struct stat *buf)
+{
+#if JCF_USE_SCANDIR
+  char *sep;
+  char *base;
+  memoized_dirlist_entry *dent;
+  void **slot;
+  
+  /* If the hashtable has not already been created, create it now.  */
+  if (!memoized_dirlists)
+    memoized_dirlists = htab_create (37,
+				     htab_hash_string,
+				     memoized_dirlist_lookup_eq,
+				     NULL);
+
+  /* Get the name of the directory.  */
+  sep = strrchr (filename, DIR_SEPARATOR);
+  if (sep)
+    {
+      *sep = '\0';
+      base = sep + 1;
+    }
+  else
+    base = filename;
+
+  /* Obtain the entry for this directory form the hash table.  */
+  slot = htab_find_slot (memoized_dirlists, filename, INSERT);
+  if (!*slot)
+    {
+      /* We have not already scanned this directory; scan it now.  */
+      dent = ((memoized_dirlist_entry *) 
+	      ALLOC (sizeof (memoized_dirlist_entry)));
+      dent->dir = xstrdup (filename);
+      /* Unfortunately, scandir is not fully standardized.  In
+	 particular, the type of the function pointer passed as the
+	 third argument sometimes takes a "const struct dirent *"
+	 parameter, and sometimes just a "struct dirent *".  We rely
+	 on the ability to interchange these two types of function
+	 pointers.  */
+      dent->num_files = scandir (filename, &dent->files, 
+				 java_or_class_file, 
+				 alphasort);
+      *slot = dent;
+    }
+  else
+    dent = *((memoized_dirlist_entry **) slot);
+
+  /* Put the spearator back.  */
+  if (sep)
+    *sep = DIR_SEPARATOR;
+
+  /* If the file is not in the list, there is no need to stat it; it
+     does not exist.  */
+  if (dent->num_files != -1
+      && !bsearch (base, dent->files, dent->num_files,
+		   sizeof (struct dirent *), compare_path))
+    return -1;
+#endif
+  
+  return stat (filename, buf);
+}
+
+/* Returns 1 if the CLASSNAME (really a char *) matches the name
+   stored in TABLE_ENTRY (also a char *).  */
+
+static int
+DEFUN(memoized_class_lookup_eq, (table_entry, classname),
+      const void *table_entry AND const void *classname)
+{
+  return strcmp ((const char *)classname, (const char *)table_entry) == 0;
+}
+
+/* A hash table keeping track of class names that were not found
+   during class lookup.  (There is no need to cache the values
+   associated with names that were found; they are saved in
+   IDENTIFIER_CLASS_VALUE.)  */
+static htab_t memoized_class_lookups;
+
 /* Returns a freshly malloc'd string with the fully qualified pathname
-   of the .class file for the class CLASSNAME.  Returns NULL on
-   failure.  If JCF != NULL, it is suitably initialized.
-   SOURCE_OK is true if we should also look for .java file. */
+   of the .class file for the class CLASSNAME.  CLASSNAME must be
+   allocated in permanent storage; this function may retain a pointer
+   to it.  Returns NULL on failure.  If JCF != NULL, it is suitably
+   initialized.  SOURCE_OK is true if we should also look for .java
+   file. */
 
 const char *
 DEFUN(find_class, (classname, classname_length, jcf, source_ok),
@@ -324,11 +471,27 @@
   char *dep_file;
   void *entry;
   char *java_buffer;
+  int buflen;
+  char *buffer;
+  hashval_t hash;
+
+  /* Create the hash table, if it does not already exist.  */
+  if (!memoized_class_lookups)
+    memoized_class_lookups = htab_create (37, 
+					  htab_hash_string, 
+					  memoized_class_lookup_eq,
+					  NULL);
+
+  /* Loop for this class in the hashtable.  If it is present, we've
+     already looked for this class and failed to find it.  */
+  hash = htab_hash_string (classname);
+  if (htab_find_with_hash (memoized_class_lookups, classname, hash))
+    return NULL;
 
   /* Allocate and zero out the buffer, since we don't explicitly put a
      null pointer when we're copying it below.  */
-  int buflen = jcf_path_max_len () + classname_length + 10;
-  char *buffer = (char *) ALLOC (buflen);
+  buflen = jcf_path_max_len () + classname_length + 10;
+  buffer = (char *) ALLOC (buflen);
   memset (buffer, 0, buflen);
 
   java_buffer = (char *) alloca (buflen);
@@ -381,7 +544,7 @@
 	      else
 		continue;
 	    }
-	  class = stat (buffer, &class_buf);
+	  class = caching_stat(buffer, &class_buf);
 	}
 
       if (source_ok)
@@ -393,7 +556,7 @@
 	  for (m = 0; m < classname_length; ++m)
 	    java_buffer[m + l] = (classname[m] == '.' ? '/' : classname[m]);
 	  strcpy (java_buffer + m + l, ".java");
-	  java = stat (java_buffer, &java_buf);
+	  java = caching_stat (java_buffer, &java_buf);
 	  if (java == 0)
 	    break;
 	}
@@ -464,6 +627,12 @@
 #endif
 
   free (buffer);
+
+  /* Remember that this class could not be found so that we do not
+     have to look again.  */
+  *htab_find_slot_with_hash (memoized_class_lookups, classname, hash, INSERT) 
+    = (void *) classname;
+
   return NULL;
  found:
 #if JCF_USE_STDIO
Index: jcf-write.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/java/jcf-write.c,v
retrieving revision 1.99.2.3
diff -u -r1.99.2.3 jcf-write.c
--- jcf-write.c	22 Apr 2002 12:53:21 -0000	1.99.2.3
+++ jcf-write.c	9 Jun 2002 02:17:03 -0000
@@ -3374,16 +3374,29 @@
 
   if (class_file_name != NULL)
     {
-      FILE *stream = fopen (class_file_name, "wb");
+      FILE *stream;
+      char *temporary_file_name;
+
+      /* The .class file is initially written to a ".tmp" file so that
+	 if multiple instances of the compiler are running at once
+	 they do not see partially formed class files. */
+      temporary_file_name = concat (class_file_name, ".tmp", NULL);
+      stream = fopen (temporary_file_name, "wb");
       if (stream == NULL)
-	fatal_io_error ("can't open %s for writing", class_file_name);
+	fatal_io_error ("can't open %s for writing", temporary_file_name);
 
       jcf_dependency_add_target (class_file_name);
       init_jcf_state (state, work);
       chunks = generate_classfile (clas, state);
       write_chunks (stream, chunks);
       if (fclose (stream))
-	fatal_io_error ("error closing %s", class_file_name);
+	fatal_io_error ("error closing %s", temporary_file_name);
+      if (rename (temporary_file_name, class_file_name) == -1)
+	{
+	  remove (temporary_file_name);
+	  fatal_io_error ("can't create %s", class_file_name);
+	}
+      free (temporary_file_name);
       free (class_file_name);
     }
   release_jcf_state (state);
Index: jcf.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/java/jcf.h,v
retrieving revision 1.28.2.2
diff -u -r1.28.2.2 jcf.h
--- jcf.h	10 Apr 2002 13:09:01 -0000	1.28.2.2
+++ jcf.h	9 Jun 2002 02:17:07 -0000
@@ -63,6 +63,14 @@
 #define JCF_word JCF_u4
 #endif
 
+/* If we have both "scandir" and "alphasort", we can cache directory
+   listings to reduce the time taken to search the classpath.  */
+#if defined(HAVE_SCANDIR) && defined(HAVE_ALPHASORT)
+#define JCF_USE_SCANDIR 1
+#else
+#define JCF_USE_SCANDIR 0
+#endif 
+
 struct JCF;
 typedef int (*jcf_filbuf_t) PARAMS ((struct JCF*, int needed));
 
Index: parse.y
===================================================================
RCS file: /cvs/gcc/gcc/gcc/java/parse.y,v
retrieving revision 1.353.2.18
diff -u -r1.353.2.18 parse.y
--- parse.y	25 Apr 2002 01:08:29 -0000	1.353.2.18
+++ parse.y	9 Jun 2002 02:19:57 -0000
@@ -9046,10 +9046,30 @@
   for (cur_ctxp = ctxp_for_generation; cur_ctxp; cur_ctxp = cur_ctxp->next)
     {
       tree current;
+      tree reversed_class_list = NULL;
+
       ctxp = cur_ctxp;
-      for (current = ctxp->class_list; current; current = TREE_CHAIN (current))
+
+      /* We write out the classes in reverse order.  This ensures that
+	 inner classes are written before their containing classes,
+	 which is important for parallel builds.  Otherwise, the
+	 class file for the outer class may be found, but the class
+	 file for the inner class may not be present.  In that
+	 situation, the compiler cannot fall back to the original
+	 source, having already read the outer class, so we must
+	 prevent that situation.  */
+      for (current = ctxp->class_list; 
+	   current; 
+	   current = TREE_CHAIN (current))
+	reversed_class_list
+	  = tree_cons (NULL_TREE, current, reversed_class_list);
+      ggc_add_tree_root (&reversed_class_list, 1);
+
+      for (current = reversed_class_list; 
+	   current; 
+	   current = TREE_CHAIN (current))
 	{
-	  current_class = TREE_TYPE (current);
+	  current_class = TREE_TYPE (TREE_VALUE (current));
 	  outgoing_cpool = TYPE_CPOOL (current_class);
 	  if (flag_emit_class_files)
 	    write_classfile (current_class);
@@ -9061,6 +9081,8 @@
 	      finish_class ();
 	    }
 	}
+
+      ggc_del_root (&reversed_class_list);
     }
 }
 


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]