Subject: Re: Reason for cygwin GCC 2.97 non-bootstrap found
From: "Zack Weinberg" <[email-masked]>
To: Kelley Cook <[email-masked]>
Cc: Cygwin mailing list <[email-masked]>, GCC Bugs <[email-masked]>, GCC Patches <[email-masked]>
Date: Mon, 20 Nov 2000 15:42:23 -0800

On Mon, Nov 20, 2000 at 05:45:26PM -0500, Kelley Cook wrote:
> After much binary searching this weekend, I discovered the reason why
> Cygwin hasn't been able to bootstrap since late August.
...
>         * ggc-page.c (alloc_page): If HAVE_MMAP_ANYWHERE and we're
>         asked for one page, allocate GGC_QUIRE_SIZE of them and put
>         the extras on the free list.

I am not familiar with Cygwin internals either.  However, the
underlying Windows primitives - MapViewOfFile, UnmapViewOfFile - do
not appear to support allocating a large chunk of memory and then
freeing bits and pieces of it, which is what the above winds up
doing.  (I am basing this on a rapid skim of the Windows API docs
available, with effort, from msdn.microsoft.com.  I may be wrong.)

That change was a marginal performance hack and I don't think it'd do
any harm to scrap it.  However, I am currently testing a patch which
moves the memory allocation mess into libiberty.  (It's a modified
version of the patch by Alexandre Oliva and Laurnyas Bivenis - less
complex, hopefully just as effective.)  I'd be curious to know how it
works on cygwin.  Patch is appended.

It'd probably be a good idea to add additional autoconf and #ifdef
logic so that xvalloc.c uses VirtualAlloc() instead of Cygwin's mmap
on Win32 hosts.

WARNING: This patch temporarily removes the ability to allocate
objects larger than one page with ggc_alloc.  I haven't yet had any
problems, but a ridiculously huge switch statement might trip over the
limitation.

NOTE: There are a bunch of technically unrelated cleanups to the
libiberty configure.in in here.

zw

gcc:
	* Makefile.in: Take out GGC, GGC_LIB; unconditionally use
	ggc-page.o in OBJS.
	(configure): Depend also on aclocal.m4.
	* aclocal.m4 (AC_FUNC_MMAP_ANYWHERE): Remove.
	(AC_FUNC_MMAP_FILE): Don't AC_REQUIRE AC_FUNC_MMAP_ANYWHERE.
	* configure.in: Don't use AC_FUNC_MMAP_ANYWHERE. Remove GGC
	selection logic.
	* configure, config.in: Regenerate.

	* ggc-page.c: Remove all code which uses mmap or valloc
	directly.  Remove code handling allocations of >1 page.  Use
	xvalloc and xvfree, provided by libiberty.

libiberty:
	* acconfig.h: Delete.
	* aclocal.m4 (libiberty_AC_PROG_CC): Move here from configure.in.
	(libiberty_FUNC_MMAP_ALLOCATION): New.
	(AC_DEFINE_NOAUTOHEADER): Temporary hack to avoid autoheader bug.
	* configure.in: Call AC_C_CONST, AC_C_INLINE, 
	libiberty_FUNC_MMAP_AUTOHEADER, and AC_CHECK_FUNCS for
	memalign, valloc, and posix_valloc.
	Use 3-arg form of AC_DEFINE in dummy declarations block, so
	acconfig.h is unnecessary.  Use AC_DEFINE_NOAUTOHEADER where
	necessary to avoid duplicate entries in config.in.

	* libiberty.h (xmalloc_failed, xvalloc, xvfree, xvalloc_init):
	New functions.
	* Makefile.in (CFILES): Add xvalloc.c.
	(REQUIRED_OFILES): Add xvalloc.o.
	(xvalloc.o): New rule.
	* xvalloc.c: New file.
	* xmalloc.c: Split out failure reporting to xmalloc_failed,
	and export it.

===================================================================
Index: gcc/Makefile.in
--- gcc/Makefile.in	2000/11/19 00:30:05	1.545
+++ gcc/Makefile.in	2000/11/20 23:27:41
@@ -358,12 +358,6 @@ CLIB=
 # system library.
 OBSTACK=obstack.o
 
-# The GC method to be used on this system.
-GGC=@GGC@.o
-
-# If a supplementary library is being used for the GC.
-GGC_LIB=
-
 # Configure will set these if you need vfprintf and possibly _doprnt support.
 VFPRINTF=@vfprintf@
 DOPRINT=@doprint@
@@ -732,10 +726,10 @@ OBJS = diagnostic.o version.o tree.o pri
  regclass.o regmove.o local-alloc.o global.o reload.o reload1.o caller-save.o \
  insn-peep.o reorg.o haifa-sched.o final.o recog.o reg-stack.o regrename.o    \
  insn-opinit.o insn-recog.o insn-extract.o insn-output.o insn-emit.o lcm.o    \
- profile.o insn-attrtab.o $(out_object_file) $(EXTRA_OBJS) convert.o	      \
- mbchar.o splay-tree.o graph.o sbitmap.o resource.o hash.o predict.o	      \
- lists.o ggc-common.o $(GGC) stringpool.o simplify-rtx.o ssa.o bb-reorder.o   \
- sibcall.o conflict.o timevar.o ifcvt.o dominance.o dependence.o dce.o
+ profile.o insn-attrtab.o convert.o mbchar.o graph.o sbitmap.o resource.o     \
+ hash.o predict.o lists.o ggc-common.o ggc-page.o stringpool.o simplify-rtx.o \
+ ssa.o bb-reorder.o sibcall.o conflict.o timevar.o ifcvt.o dominance.o dce.o  \
+ dependence.o $(out_object_file) $(EXTRA_OBJS) 
 
 BACKEND = toplev.o libbackend.a
 
@@ -862,7 +856,7 @@ Makefile: $(srcdir)/Makefile.in config.s
 	LANGUAGES="$(CONFIG_LANGUAGES)" $(SHELL) config.run
 	rm -f config.run
 
-$(srcdir)/configure: $(srcdir)/configure.in
+$(srcdir)/configure: $(srcdir)/configure.in $(srcdir)/aclocal.m4
 	(cd $(srcdir) && autoconf)
 
 gccbug:	$(srcdir)/gccbug.in
===================================================================
Index: gcc/aclocal.m4
--- gcc/aclocal.m4	2000/10/09 08:36:36	1.37
+++ gcc/aclocal.m4	2000/11/20 23:27:42
@@ -734,104 +734,9 @@ fi
 AC_SUBST($1)dnl
 ])
 
-# Check whether mmap can map an arbitrary page from /dev/zero or with
-# MAP_ANONYMOUS, without MAP_FIXED.
-AC_DEFUN([AC_FUNC_MMAP_ANYWHERE],
-[AC_CHECK_HEADERS(unistd.h)
-AC_CHECK_FUNCS(getpagesize)
-AC_CACHE_CHECK(for working mmap which provides zeroed pages anywhere,
-  ac_cv_func_mmap_anywhere,
-[AC_TRY_RUN([
-/* Test by Richard Henderson and Alexandre Oliva.
-   Check whether mmap MAP_ANONYMOUS or mmap from /dev/zero works. */
-#include <sys/types.h>
-#include <fcntl.h>
-#include <sys/mman.h>
-
-#if !defined (MAP_ANONYMOUS) && defined (MAP_ANON)
-# define MAP_ANONYMOUS MAP_ANON
-#endif
-
-/* This mess was copied from the GNU getpagesize.h.  */
-#ifndef HAVE_GETPAGESIZE
-# ifdef HAVE_UNISTD_H
-#  include <unistd.h>
-# endif
-
-/* Assume that all systems that can run configure have sys/param.h.  */
-# ifndef HAVE_SYS_PARAM_H
-#  define HAVE_SYS_PARAM_H 1
-# endif
-
-# ifdef _SC_PAGESIZE
-#  define getpagesize() sysconf(_SC_PAGESIZE)
-# else /* no _SC_PAGESIZE */
-#  ifdef HAVE_SYS_PARAM_H
-#   include <sys/param.h>
-#   ifdef EXEC_PAGESIZE
-#    define getpagesize() EXEC_PAGESIZE
-#   else /* no EXEC_PAGESIZE */
-#    ifdef NBPG
-#     define getpagesize() NBPG * CLSIZE
-#     ifndef CLSIZE
-#      define CLSIZE 1
-#     endif /* no CLSIZE */
-#    else /* no NBPG */
-#     ifdef NBPC
-#      define getpagesize() NBPC
-#     else /* no NBPC */
-#      ifdef PAGESIZE
-#       define getpagesize() PAGESIZE
-#      endif /* PAGESIZE */
-#     endif /* no NBPC */
-#    endif /* no NBPG */
-#   endif /* no EXEC_PAGESIZE */
-#  else /* no HAVE_SYS_PARAM_H */
-#   define getpagesize() 8192	/* punt totally */
-#  endif /* no HAVE_SYS_PARAM_H */
-# endif /* no _SC_PAGESIZE */
-
-#endif /* no HAVE_GETPAGESIZE */
-
-int main()
-{
-  char *x;
-  int fd, pg;
-
-#ifndef MAP_ANONYMOUS
-  fd = open("/dev/zero", O_RDWR);
-  if (fd < 0)
-    exit(1);
-#endif
-
-  pg = getpagesize();
-#ifdef MAP_ANONYMOUS
-  x = (char*)mmap(0, pg, PROT_READ|PROT_WRITE,
-                  MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
-#else
-  x = (char*)mmap(0, pg, PROT_READ|PROT_WRITE, MAP_PRIVATE, fd, 0);
-#endif
-  if (x == (char *) -1)
-    exit(2);
-
-  *(int *)x += 1;
-
-  if (munmap(x, pg) < 0)
-    exit(3);
-
-  exit(0);
-}], ac_cv_func_mmap_anywhere=yes, ac_cv_func_mmap_anywhere=no,
-ac_cv_func_mmap_anywhere=no)])
-if test $ac_cv_func_mmap_anywhere = yes; then
-  AC_DEFINE(HAVE_MMAP_ANYWHERE, 1,
-	    [Define if mmap can get us zeroed pages without MAP_FIXED.])
-fi
-])
-
 # Check whether mmap can map a plain file, without MAP_FIXED.
-AC_DEFUN([AC_FUNC_MMAP_FILE], 
-[AC_REQUIRE([AC_FUNC_MMAP_ANYWHERE])dnl
-AC_CACHE_CHECK(for working mmap of a file, ac_cv_func_mmap_file,
+AC_DEFUN(AC_FUNC_MMAP_FILE, 
+[AC_CACHE_CHECK(for working mmap of a file, ac_cv_func_mmap_file,
 [# Create a file one thousand bytes long.
 for i in 1 2 3 4 5 6 7 8 9 0
 do for j in 1 2 3 4 5 6 7 8 9 0
===================================================================
Index: gcc/configure.in
--- gcc/configure.in	2000/11/19 05:00:10	1.455
+++ gcc/configure.in	2000/11/20 23:27:44
@@ -581,7 +581,6 @@ case "${host}" in
   ;;
 esac
 AC_FUNC_VFORK
-AC_FUNC_MMAP_ANYWHERE
 AC_FUNC_MMAP_FILE
 
 # We will need to find libiberty.h and ansidecl.h
@@ -1566,27 +1565,6 @@ if test $thread_file != single; then
     gthread_flags=-DHAVE_GTHR_DEFAULT
 fi
 AC_SUBST(gthread_flags)
-
-# Find out what GC implementation we want, or may, use.
-AC_ARG_WITH(gc,
-[  --with-gc={simple,page} Choose the garbage collection mechanism to use
-                           with the compiler.],
-[case "$withval" in
-  simple | page)
-    GGC=ggc-$withval
-    ;;
-  *)
-    AC_MSG_ERROR([$withval is an invalid option to --with-gc])
-    ;;
-esac],
-[if test $ac_cv_func_mmap_anywhere = yes \
-    || test $ac_cv_func_valloc = yes; then
-  GGC=ggc-page
-else
-  GGC=ggc-simple
-fi])
-AC_SUBST(GGC)
-echo "Using $GGC for garbage collection."
 
 # Use the system's zlib library.
 zlibdir=-L../zlib
===================================================================
Index: gcc/ggc-page.c
--- gcc/ggc-page.c	2000/11/17 06:05:15	1.31
+++ gcc/ggc-page.c	2000/11/20 23:27:44
@@ -28,19 +28,8 @@ Boston, MA 02111-1307, USA.  */
 #include "flags.h"
 #include "ggc.h"
 #include "timevar.h"
+#include "libiberty.h"
 
-#ifdef HAVE_MMAP_ANYWHERE
-#include <sys/mman.h>
-#endif
-
-#ifndef MAP_FAILED
-#define MAP_FAILED -1
-#endif
-
-#if !defined (MAP_ANONYMOUS) && defined (MAP_ANON)
-#define MAP_ANONYMOUS MAP_ANON
-#endif
-
 /* Stategy: 
 
    This garbage-collecting allocator allocates objects on one of a set
@@ -142,10 +131,6 @@ typedef struct page_entry 
      this is the last page-entry.  */
   struct page_entry *next;
 
-  /* The number of bytes allocated.  (This will always be a multiple
-     of the host system page size.)  */
-  size_t bytes;
-
   /* The address at which the memory is allocated.  */
   char *page;
 
@@ -198,7 +183,8 @@ static struct globals
   /* The Nth element in this array is a page with objects of size 2^N.
      If there are any pages with free objects, they will be at the
      head of the list.  NULL if there are no page-entries for this
-     object size.  */
+     object size.  Note that only the entries through G.lg_pagesize are
+     actually used.  */
   page_entry *pages[HOST_BITS_PER_PTR];
 
   /* The Nth element in this array is the last page with objects of
@@ -225,11 +211,6 @@ static struct globals
   /* The current depth in the context stack.  */
   unsigned short context_depth;
 
-  /* A file descriptor open to /dev/zero for reading.  */
-#if defined (HAVE_MMAP_ANYWHERE) && !defined(MAP_ANONYMOUS)
-  int dev_zero_fd;
-#endif
-
   /* A cache of free system pages.  */
   page_entry *free_pages;
 
@@ -243,9 +224,8 @@ static struct globals
   (((Dividend) + (Divisor) - 1) / (Divisor))
 
 /* The number of objects per allocation page, for objects of size
-   2^ORDER.  */
-#define OBJECTS_PER_PAGE(Order) \
-  ((Order) >= G.lg_pagesize ? 1 : G.pagesize / ((size_t)1 << (Order)))
+   2^ORDER.  Note that ORDER may not go above log2(G.pagesize).  */
+#define OBJECTS_PER_PAGE(Order) (G.pagesize / ((size_t)1 << (Order)))
 
 /* The size in bytes required to maintain a bitmap for the objects
    on a page-entry.  */
@@ -270,7 +250,6 @@ static struct globals
 static int ggc_allocated_p PARAMS ((const void *));
 static page_entry *lookup_page_table_entry PARAMS ((const void *));
 static void set_page_table_entry PARAMS ((void *, page_entry *));
-static char *alloc_anon PARAMS ((char *, size_t));
 static struct page_entry * alloc_page PARAMS ((unsigned));
 static void free_page PARAMS ((struct page_entry *));
 static void release_pages PARAMS ((void));
@@ -401,46 +380,6 @@ debug_print_page_list (order)
   fflush (stdout);
 }
 
-/* Allocate SIZE bytes of anonymous memory, preferably near PREF,
-   (if non-null).  */
-
-static inline char *
-alloc_anon (pref, size)
-     char *pref ATTRIBUTE_UNUSED;
-     size_t size;
-{
-  char *page;
-
-#ifdef HAVE_MMAP_ANYWHERE
-#ifdef MAP_ANONYMOUS
-  page = (char *) mmap (pref, size, PROT_READ | PROT_WRITE,
-			MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
-#else
-  page = (char *) mmap (pref, size, PROT_READ | PROT_WRITE,
-			MAP_PRIVATE, G.dev_zero_fd, 0);
-#endif
-  if (page == (char *) MAP_FAILED)
-    {
-      fputs ("Virtual memory exhausted!\n", stderr);
-      exit(1);
-    }
-#else
-#ifdef HAVE_VALLOC
-  page = (char *) valloc (size);
-  if (!page)
-    {
-      fputs ("Virtual memory exhausted!\n", stderr);
-      exit(1);
-    }
-#endif /* HAVE_VALLOC */
-#endif /* HAVE_MMAP_ANYWHERE */
-
-  /* Remember that we allocated this memory.  */
-  G.bytes_mapped += size;
-
-  return page;
-}
-
 /* Allocate a new page for allocating objects of size 2^ORDER,
    and return an entry for it.  The entry is not added to the
    appropriate page_table list.  */
@@ -449,30 +388,30 @@ static inline struct page_entry *
 alloc_page (order)
      unsigned order;
 {
-  struct page_entry *entry, *p, **pp;
+  struct page_entry *entry, *p;
   char *page;
   size_t num_objects;
   size_t bitmap_size;
   size_t page_entry_size;
-  size_t entry_size;
 
   num_objects = OBJECTS_PER_PAGE (order);
   bitmap_size = BITMAP_SIZE (num_objects + 1);
   page_entry_size = sizeof (page_entry) - sizeof (long) + bitmap_size;
-  entry_size = num_objects * (1 << order);
 
+#ifdef ENABLE_CHECKING
+  if (num_objects * (1 << order) != G.pagesize)
+    abort ();
+#endif
+
   entry = NULL;
   page = NULL;
 
-  /* Check the list of free pages for one we can use.  */
-  for (pp = &G.free_pages, p = *pp; p ; pp = &p->next, p = *pp)
-    if (p->bytes == entry_size)
-      break;
+  p = G.free_pages;
 
   if (p != NULL)
     {
       /* Recycle the allocated memory from this page ... */
-      *pp = p->next;
+      G.free_pages = p->next;
       page = p->page;
       /* ... and, if possible, the page entry itself.  */
       if (p->order == order)
@@ -483,36 +422,17 @@ alloc_page (order)
       else
 	free (p);
     }
-#ifdef HAVE_MMAP_ANYWHERE
-  else if (entry_size == G.pagesize)
+  else
     {
-      /* We want just one page.  Allocate a bunch of them and put the
-	 extras on the freelist.  (Can only do this optimization with
-	 mmap for backing store.)  */
-      struct page_entry *e, *f = G.free_pages;
-      int i;
-
-      page = alloc_anon (NULL, entry_size * GGC_QUIRE_SIZE);
-      /* This loop counts down so that the chain will be in ascending
-	 memory order.  */
-      for (i = GGC_QUIRE_SIZE - 1; i >= 1; i--)
-	{
-	  e = (struct page_entry *) xcalloc (1, sizeof (struct page_entry));
-	  e->bytes = entry_size;
-	  e->page = page + i*entry_size;
-	  e->next = f;
-	  f = e;
-	}
-      G.free_pages = f;
+      page = xvalloc (G.pagesize);
+      /* Remember that we allocated this memory.  */
+      G.bytes_mapped += G.pagesize;
     }
-#endif
-  else
-    page = alloc_anon (NULL, entry_size);
+
 
   if (entry == NULL)
     entry = (struct page_entry *) xcalloc (1, page_entry_size);
 
-  entry->bytes = entry_size;
   entry->page = page;
   entry->context_depth = G.context_depth;
   entry->order = order;
@@ -527,9 +447,8 @@ alloc_page (order)
   set_page_table_entry (page, entry);
 
   if (GGC_DEBUG_LEVEL >= 2)
-    fprintf (G.debug_file, 
-	     "Allocating page at %p, object size=%d, data %p-%p\n",
-	     (PTR) entry, 1 << order, page, page + entry_size - 1);
+    fprintf (G.debug_file, "Allocating page at %p, object size=%d\n",
+	     (PTR) entry, 1 << order);
 
   return entry;
 }
@@ -542,8 +461,7 @@ free_page (entry)
 {
   if (GGC_DEBUG_LEVEL >= 2)
     fprintf (G.debug_file, 
-	     "Deallocating page at %p, data %p-%p\n", (PTR) entry,
-	     entry->page, entry->page + entry->bytes - 1);
+	     "Deallocating page at %p\n", (PTR) entry);
 
   set_page_table_entry (entry->page, NULL);
 
@@ -558,44 +476,13 @@ release_pages ()
 {
   page_entry *p, *next;
 
-#ifdef HAVE_MMAP_ANYWHERE
-  char *start;
-  size_t len;
-
-  /* Gather up adjacent pages so they are unmapped together.  */
-  p = G.free_pages;
-
-  while (p)
-    {
-      start = p->page;
-      next = p->next;
-      len = p->bytes;
-      free (p);
-      p = next;
-
-      while (p && p->page == start + len)
-	{
-	  next = p->next;
-	  len += p->bytes;
-	  free (p);
-	  p = next;
-	}
-
-      munmap (start, len);
-      G.bytes_mapped -= len;
-    }
-#else
-#ifdef HAVE_VALLOC
-
   for (p = G.free_pages; p; p = next)
     {
       next = p->next;
-      free (p->page);
-      G.bytes_mapped -= p->bytes;
+      xvfree (p->page, G.pagesize);
+      G.bytes_mapped -= G.pagesize;
       free (p);
     }
-#endif /* HAVE_VALLOC */
-#endif /* HAVE_MMAP_ANYWHERE */
 
   G.free_pages = NULL;
 }
@@ -635,6 +522,9 @@ ggc_alloc (size)
   struct page_entry *entry;
   void *result;
 
+  if (size > G.pagesize)
+    fatal ("cannot ggc_alloc %d byte chunk, larger than one page", size);
+
   if (size <= 256)
     order = size_lookup[size];
   else
@@ -803,12 +693,7 @@ init_ggc ()
 {
   G.pagesize = getpagesize();
   G.lg_pagesize = exact_log2 (G.pagesize);
-
-#if defined (HAVE_MMAP_ANYWHERE) && !defined(MAP_ANONYMOUS)
-  G.dev_zero_fd = open ("/dev/zero", O_RDONLY);
-  if (G.dev_zero_fd == -1)
-    abort ();
-#endif
+  G.allocated_last_gc = GGC_MIN_LAST_ALLOCATED;
 
 #if 0
   G.debug_file = fopen ("ggc-mmap.debug", "w");
@@ -816,27 +701,7 @@ init_ggc ()
   G.debug_file = stdout;
 #endif
 
-  G.allocated_last_gc = GGC_MIN_LAST_ALLOCATED;
-
-#ifdef HAVE_MMAP_ANYWHERE
-  /* StunOS has an amazing off-by-one error for the first mmap allocation
-     after fiddling with RLIMIT_STACK.  The result, as hard as it is to
-     believe, is an unaligned page allocation, which would cause us to
-     hork badly if we tried to use it.  */
-  {
-    char *p = alloc_anon (NULL, G.pagesize);
-    if ((size_t)p & (G.pagesize - 1))
-      {
-	/* How losing.  Discard this one and try another.  If we still
-	   can't get something useful, give up.  */
-
-	p = alloc_anon (NULL, G.pagesize);
-	if ((size_t)p & (G.pagesize - 1))
-	  abort ();
-      }
-    munmap (p, G.pagesize);
-  }
-#endif
+  xvalloc_init ();
 }
 
 /* Increment the `GC context'.  Objects allocated in an outer context
@@ -903,7 +768,7 @@ ggc_pop_context ()
   /* Any remaining pages in the popped context are lowered to the new
      current context; i.e. objects allocated in the popped context and
      left over are imported into the previous context.  */
-  for (order = 2; order < HOST_BITS_PER_PTR; order++)
+  for (order = 2; order <= G.lg_pagesize; order++)
     {
       page_entry *p;
 
@@ -931,7 +796,7 @@ clear_marks ()
 {
   unsigned order;
 
-  for (order = 2; order < HOST_BITS_PER_PTR; order++)
+  for (order = 2; order <= G.lg_pagesize; order++)
     {
       size_t num_objects = OBJECTS_PER_PAGE (order);
       size_t bitmap_size = BITMAP_SIZE (num_objects + 1);
@@ -975,7 +840,7 @@ sweep_pages ()
 {
   unsigned order;
 
-  for (order = 2; order < HOST_BITS_PER_PTR; order++)
+  for (order = 2; order <= G.lg_pagesize; order++)
     {
       /* The last page-entry to consider, regardless of entries
 	 placed at the end of the list.  */
@@ -1082,7 +947,7 @@ poison_pages ()
 {
   unsigned order;
 
-  for (order = 2; order < HOST_BITS_PER_PTR; order++)
+  for (order = 2; order <= G.lg_pagesize; order++)
     {
       size_t num_objects = OBJECTS_PER_PAGE (order);
       size_t size = (size_t) 1 << order;
@@ -1188,7 +1053,7 @@ ggc_print_statistics ()
      allocation.  */
   fprintf (stderr, "\n%-5s %10s  %10s  %10s\n",
 	   "Log", "Allocated", "Used", "Overhead");
-  for (i = 0; i < HOST_BITS_PER_PTR; ++i)
+  for (i = 0; i <= G.lg_pagesize; ++i)
     {
       page_entry *p;
       size_t allocated;
@@ -1206,7 +1071,7 @@ ggc_print_statistics ()
 	 out how much memory the page table is using.  */
       for (p = G.pages[i]; p; p = p->next)
 	{
-	  allocated += p->bytes;
+	  allocated += G.pagesize;
 	  in_use += 
 	    (OBJECTS_PER_PAGE (i) - p->num_free_objects) * (1 << i);
 
===================================================================
Index: include/libiberty.h
--- include/libiberty.h	2000/08/24 20:28:15	1.13
+++ include/libiberty.h	2000/11/20 23:27:45
@@ -126,20 +126,25 @@ extern int xatexit PARAMS ((void (*fn) (
 
 extern void xexit PARAMS ((int status)) ATTRIBUTE_NORETURN;
 
+#ifdef ANSI_PROTOTYPES
+/* Get a definition for size_t.  */
+#include <stddef.h>
+/* Get a definition for va_list.  */
+#include <stdarg.h>
+#endif
+
 /* Set the program name used by xmalloc.  */
 
 extern void xmalloc_set_program_name PARAMS ((const char *));
 
+/* Report memory allocation failure.  */
+
+extern void xmalloc_failed PARAMS ((size_t)) ATTRIBUTE_NORETURN;
+
 /* Allocate memory without fail.  If malloc fails, this will print a
    message to stderr (using the name set by xmalloc_set_program_name,
    if any) and then call xexit.  */
 
-#ifdef ANSI_PROTOTYPES
-/* Get a definition for size_t.  */
-#include <stddef.h>
-/* Get a definition for va_list.  */
-#include <stdarg.h>
-#endif
 extern PTR xmalloc PARAMS ((size_t)) ATTRIBUTE_MALLOC;
 
 /* Reallocate memory without fail.  This works like xmalloc.  Note,
@@ -160,6 +165,19 @@ extern char *xstrdup PARAMS ((const char
 /* Copy an existing memory buffer to a new memory buffer without fail.  */
 
 extern PTR xmemdup PARAMS ((const PTR, size_t, size_t)) ATTRIBUTE_MALLOC;
+
+/* Allocate a page-aligned memory block without fail.  This may use mmap,
+   so you must use xvfree to free memory allocated by xvalloc.  */
+
+extern char *xvalloc PARAMS ((size_t)) ATTRIBUTE_MALLOC;
+
+/* Release memory allocated by xvalloc.  */
+
+extern void xvfree PARAMS ((char *, size_t));
+
+/* Initialize xvalloc internal structures.  Must be called before
+   xvalloc is used.  */
+extern void xvalloc_init PARAMS ((void));
 
 /* hex character manipulation routines */
 
===================================================================
Index: libiberty/Makefile.in
--- libiberty/Makefile.in	2000/08/29 04:35:59	1.54
+++ libiberty/Makefile.in	2000/11/20 23:27:45
@@ -135,7 +135,7 @@ CFILES = asprintf.c alloca.c argv.c atex
 	strchr.c strdup.c strerror.c strncmp.c strrchr.c strsignal.c strstr.c \
 	strtod.c strtol.c strtoul.c tmpnam.c vasprintf.c vfork.c vfprintf.c   \
 	vprintf.c vsprintf.c waitpid.c xatexit.c xexit.c xmalloc.c	      \
-	xmemdup.c xstrdup.c xstrerror.c
+	xmemdup.c xstrdup.c xstrerror.c xvalloc.c
 
 # These are always included in the library.
 REQUIRED_OFILES = argv.o choose-temp.o concat.o cplus-dem.o cp-demangle.o \
@@ -143,7 +143,7 @@ REQUIRED_OFILES = argv.o choose-temp.o c
 	getruntime.o hashtab.o hex.o floatformat.o md5.o objalloc.o obstack.o \
 	partition.o pexecute.o sort.o spaces.o splay-tree.o strerror.o	  \
 	strsignal.o xatexit.o xexit.o xmalloc.o xmemdup.o xstrdup.o	  \
-	xstrerror.o
+	xstrerror.o xvalloc.o
 
 $(TARGETLIB): $(REQUIRED_OFILES) $(EXTRA_OFILES) $(LIBOBJS) $(ALLOCA)
 	rm -f $(TARGETLIB)
@@ -297,5 +297,6 @@ xmalloc.o: config.h $(INCDIR)/libiberty.
 xmemdup.o: config.h $(INCDIR)/libiberty.h
 xstrdup.o: config.h $(INCDIR)/libiberty.h
 xstrerror.o: config.h $(INCDIR)/libiberty.h
+xvalloc.o: config.h $(INCDIR)/libiberty.h
 waitpid.o: config.h
 hashtab.o: config.h $(INCDIR)/libiberty.h $(INCDIR)/hashtab.h $(INCDIR)/ansidecl.h
===================================================================
Index: libiberty/acconfig.h
--- libiberty/acconfig.h	1999/09/04 15:08:49	1.2
+++ libiberty/acconfig.h	2000/11/20 23:27:45
@@ -1,11 +0,0 @@
-/* Define if you have the sys_errlist variable.  */
-#undef HAVE_SYS_ERRLIST
-
-/* Define if you have the sys_nerr variable.  */
-#undef HAVE_SYS_NERR
-
-/* Define if you have the sys_siglist variable.  */
-#undef HAVE_SYS_SIGLIST
-
-/* Define if you have the strerror function.  */
-#undef HAVE_STRERROR
===================================================================
Index: libiberty/aclocal.m4
--- libiberty/aclocal.m4	2000/07/23 16:05:03	1.2
+++ libiberty/aclocal.m4	2000/11/20 23:27:45
@@ -83,3 +83,174 @@ then AC_DEFINE(NEED_DECLARATION_ERRNO, 1
   [Define if errno must be declared even when <errno.h> is included.])
 fi
 ])
+
+dnl FIXME: We temporarily define our own version of AC_PROG_CC.  This is
+dnl copied from autoconf 2.12, but does not call AC_PROG_CC_WORKS.  We
+dnl are probably using a cross compiler, which will not be able to fully
+dnl link an executable.  This should really be fixed in autoconf
+dnl itself.
+AC_DEFUN(libiberty_AC_PROG_CC,
+[AC_BEFORE([$0], [AC_PROG_CPP])dnl
+AC_PROVIDE([AC_PROG_CC])
+AC_CHECK_PROG(CC, gcc, gcc)
+if test -z "$CC"; then
+  AC_CHECK_PROG(CC, cc, cc, , , /usr/ucb/cc)
+  test -z "$CC" && AC_MSG_ERROR([no acceptable cc found in \$PATH])
+fi
+
+AC_PROG_CC_GNU
+
+if test $ac_cv_prog_gcc = yes; then
+  GCC=yes
+  ac_libiberty_warn_cflags='-W -Wall -Wtraditional -pedantic'
+dnl Check whether -g works, even if CFLAGS is set, in case the package
+dnl plays around with CFLAGS (such as to build both debugging and
+dnl normal versions of a library), tasteless as that idea is.
+  ac_test_CFLAGS="${CFLAGS+set}"
+  ac_save_CFLAGS="$CFLAGS"
+  CFLAGS=
+  AC_PROG_CC_G
+  if test "$ac_test_CFLAGS" = set; then
+    CFLAGS="$ac_save_CFLAGS"
+  elif test $ac_cv_prog_cc_g = yes; then
+    CFLAGS="-g -O2"
+  else
+    CFLAGS="-O2"
+  fi
+else
+  GCC=
+  ac_libiberty_warn_cflags=
+  test "${CFLAGS+set}" = set || CFLAGS="-g"
+fi
+AC_SUBST(ac_libiberty_warn_cflags)
+])
+
+dnl Check whether we can use mmap to allocate memory, with no
+dnl specification of the address to allocate at.
+dnl Defines HAVE_MMAP_ANON and HAVE_MMAP_DEV_ZERO, depending on which
+dnl technique you have to use.
+AC_DEFUN([libiberty_FUNC_MMAP_ALLOCATION],
+[AC_CHECK_HEADERS(unistd.h)
+AC_CHECK_FUNCS(getpagesize)
+cat >ct-mmap.inc <<'__END_OF_FILE__'
+/* Test by Richard Henderson and Alexandre Oliva.
+   Check whether mmap from /dev/zero works. */
+#include <sys/types.h>
+#include <fcntl.h>
+#include <sys/mman.h>
+
+/* This mess was copied from the GNU getpagesize.h.  */
+#ifndef HAVE_GETPAGESIZE
+# ifdef HAVE_UNISTD_H
+#  include <unistd.h>
+# endif
+
+/* Assume that all systems that can run configure have sys/param.h.  */
+# ifndef HAVE_SYS_PARAM_H
+#  define HAVE_SYS_PARAM_H 1
+# endif
+
+# ifdef _SC_PAGESIZE
+#  define getpagesize() sysconf(_SC_PAGESIZE)
+# else /* no _SC_PAGESIZE */
+#  ifdef HAVE_SYS_PARAM_H
+#   include <sys/param.h>
+#   ifdef EXEC_PAGESIZE
+#    define getpagesize() EXEC_PAGESIZE
+#   else /* no EXEC_PAGESIZE */
+#    ifdef NBPG
+#     define getpagesize() NBPG * CLSIZE
+#     ifndef CLSIZE
+#      define CLSIZE 1
+#     endif /* no CLSIZE */
+#    else /* no NBPG */
+#     ifdef NBPC
+#      define getpagesize() NBPC
+#     else /* no NBPC */
+#      ifdef PAGESIZE
+#       define getpagesize() PAGESIZE
+#      endif /* PAGESIZE */
+#     endif /* no NBPC */
+#    endif /* no NBPG */
+#   endif /* no EXEC_PAGESIZE */
+#  else /* no HAVE_SYS_PARAM_H */
+#   define getpagesize() 8192  /* punt totally */
+#  endif /* no HAVE_SYS_PARAM_H */
+# endif /* no _SC_PAGESIZE */
+
+#endif /* no HAVE_GETPAGESIZE */
+
+#ifdef USE_DEV_ZERO
+# undef MAP_ANONYMOUS
+# define MAP_ANONYMOUS 0
+#else
+# if !defined MAP_ANONYMOUS && defined MAP_ANON
+#  define MAP_ANONYMOUS MAP_ANON
+# endif
+#endif
+
+int main()
+{
+  char *x;
+  int pg;
+
+#ifdef USE_DEV_ZERO
+  int fd;
+ 
+  fd = open("/dev/zero", O_RDWR);
+  if (fd < 0)
+    exit(1);
+#else
+# define fd -1
+#endif
+
+  pg = getpagesize();
+  x = (char*)mmap(0, pg, PROT_READ|PROT_WRITE, 
+		  MAP_PRIVATE|MAP_ANONYMOUS, fd, 0);
+  if (x == (char *) -1)
+    exit(2);
+
+  *(int *)x += 1;
+
+  if (munmap(x, pg) < 0)
+    exit(3);
+
+  exit(0);
+}
+__END_OF_FILE__
+
+AC_CACHE_CHECK(for working mmap with MAP_ANON, ac_cv_func_mmap_anon,
+[AC_TRY_RUN(
+[#include "ct-mmap.inc"],
+ ac_cv_func_mmap_anon=yes,
+ ac_cv_func_mmap_anon=no,
+ ac_cv_func_mmap_anon=no)
+])
+if test $ac_cv_func_mmap_anon = yes; then
+  AC_DEFINE(HAVE_MMAP_ANON, 1,
+           [Define if mmap can get us zeroed pages with MAP_ANON(YMOUS).])
+fi
+
+AC_CACHE_CHECK(for working mmap from /dev/zero, ac_cv_func_mmap_dev_zero,
+[AC_TRY_RUN(
+[#define USE_DEV_ZERO
+#include "ct-mmap.inc"],
+ ac_cv_func_mmap_dev_zero=yes,
+ ac_cv_func_mmap_dev_zero=no,
+ ac_cv_func_mmap_dev_zero=no)
+])
+if test $ac_cv_func_mmap_dev_zero = yes; then
+  AC_DEFINE(HAVE_MMAP_DEV_ZERO, 1,
+           [Define if mmap can get us zeroed pages from /dev/zero.])
+fi
+rm -f ct-mmap.inc
+])
+
+dnl This hack works around a bug in autoheader.  Take out after we
+dnl start insisting on autoconf >2.50.
+dnl Use of 'define' not 'AC_DEFUN' is deliberate.
+define(AC_DEFINE_NOAUTOHEADER,
+[cat >> confdefs.h <<\EOF
+[#define] $1 ifelse($#, 2, [$2], $#, 3, [$2], 1)
+EOF
+])
===================================================================
Index: libiberty/configure.in
--- libiberty/configure.in	2000/09/05 18:43:26	1.29
+++ libiberty/configure.in	2000/11/20 23:27:46
@@ -36,51 +36,11 @@ dnl to call AC_CHECK_PROG.
 AC_CHECK_TOOL(AR, ar)
 AC_CHECK_TOOL(RANLIB, ranlib, :)
 
-# FIXME: We temporarily define our own version of AC_PROG_CC.  This is
-# copied from autoconf 2.12, but does not call AC_PROG_CC_WORKS.  We
-# are probably using a cross compiler, which will not be able to fully
-# link an executable.  This should really be fixed in autoconf
-# itself.
-
-AC_DEFUN(LIB_AC_PROG_CC,
-[AC_BEFORE([$0], [AC_PROG_CPP])dnl
-AC_PROVIDE([AC_PROG_CC])
-AC_CHECK_PROG(CC, gcc, gcc)
-if test -z "$CC"; then
-  AC_CHECK_PROG(CC, cc, cc, , , /usr/ucb/cc)
-  test -z "$CC" && AC_MSG_ERROR([no acceptable cc found in \$PATH])
-fi
-
-AC_PROG_CC_GNU
-
-if test $ac_cv_prog_gcc = yes; then
-  GCC=yes
-  ac_libiberty_warn_cflags='-W -Wall -Wtraditional -pedantic'
-dnl Check whether -g works, even if CFLAGS is set, in case the package
-dnl plays around with CFLAGS (such as to build both debugging and
-dnl normal versions of a library), tasteless as that idea is.
-  ac_test_CFLAGS="${CFLAGS+set}"
-  ac_save_CFLAGS="$CFLAGS"
-  CFLAGS=
-  AC_PROG_CC_G
-  if test "$ac_test_CFLAGS" = set; then
-    CFLAGS="$ac_save_CFLAGS"
-  elif test $ac_cv_prog_cc_g = yes; then
-    CFLAGS="-g -O2"
-  else
-    CFLAGS="-O2"
-  fi
-else
-  GCC=
-  ac_libiberty_warn_cflags=
-  test "${CFLAGS+set}" = set || CFLAGS="-g"
-fi
-])
-AC_SUBST(ac_libiberty_warn_cflags)
+libiberty_AC_PROG_CC
 
-LIB_AC_PROG_CC
-
 AC_ISC_POSIX
+AC_C_CONST
+AC_C_INLINE
 
 dnl When we start using libtool:
 dnl Default to a non shared library.  This may be overridden by the
@@ -172,11 +132,11 @@ if test "x" = "y"; then
   AC_CHECK_FUNCS(memset putenv random rename rindex sigsetmask strcasecmp)
   AC_CHECK_FUNCS(setenv strchr strdup strncasecmp strrchr strstr strtod strtol)
   AC_CHECK_FUNCS(strtoul tmpnam vasprintf vfprintf vprintf vsprintf waitpid)
-  AC_DEFINE(HAVE_SYS_ERRLIST)
-  AC_DEFINE(HAVE_SYS_NERR)
-  AC_DEFINE(HAVE_SYS_SIGLIST)
   AC_CHECK_FUNCS(getrusage on_exit psignal strerror strsignal sysconf times)
   AC_CHECK_FUNCS(sbrk gettimeofday)
+  AC_DEFINE(HAVE_SYS_ERRLIST, 1, [Define if you have the sys_errlist variable.])
+  AC_DEFINE(HAVE_SYS_NERR, 1, [Define if you have the sys_nerr variable.])
+  AC_DEFINE(HAVE_SYS_SIGLIST, 1, [Define if you have the sys_siglist variable.])
 fi
 
 # For each of these functions, if the host does not provide the
@@ -215,7 +175,7 @@ if test -n "${with_target_subdir}"; then
     # dont have to check them here.
 
     # Of the functions in $checkfuncs, newlib only has strerror.
-    AC_DEFINE(HAVE_STRERROR)
+    AC_DEFINE_NOAUTOHEADER(HAVE_STRERROR)
 
     setobjs=yes
 
@@ -256,7 +216,7 @@ if test -z "${setobjs}"; then
     # don't have to check them here.
 
     # Of the functions in $checkfuncs, VxWorks only has strerror.
-    AC_DEFINE(HAVE_STRERROR)
+    AC_DEFINE_NOAUTOHEADER(HAVE_STRERROR)
 
     setobjs=yes
     ;;
@@ -294,9 +254,8 @@ if test -z "${setobjs}"; then
   *-*-mingw32*)
     # Under mingw32, sys_nerr and sys_errlist exist, but they are
     # macros, so the test below won't find them.
-    vars="`echo $vars | sed -e 's/sys_nerr//' -e 's/sys_errlist//'`"
-    AC_DEFINE(HAVE_SYS_NERR)
-    AC_DEFINE(HAVE_SYS_ERRLIST)
+    libiberty_cv_var_sys_nerr=yes
+    libiberty_cv_var_sys_errlist=yes
     ;;
 
   *-*-uwin*)
@@ -307,8 +266,8 @@ if test -z "${setobjs}"; then
     # Under uwin 2.0+, sys_nerr and sys_errlist exist, but they are
     # macros (actually, these are imported from a DLL, but the end effect 
     # is the same), so the test below won't find them.
-    AC_DEFINE(HAVE_SYS_NERR)
-    AC_DEFINE(HAVE_SYS_ERRLIST)
+    libiberty_cv_var_sys_nerr=yes
+    libiberty_cv_var_sys_errlist=yes
     ;;
 
   esac
@@ -361,6 +320,10 @@ EOF
 fi
 
 libiberty_AC_FUNC_STRNCMP
+
+# These are used by xvalloc.c
+libiberty_FUNC_MMAP_ALLOCATION
+AC_CHECK_FUNCS(memalign valloc posix_valloc)
 
 # Install a library built with a cross compiler in $(tooldir) rather
 # than $(libdir).
===================================================================
Index: libiberty/xmalloc.c
--- libiberty/xmalloc.c	2000/05/18 22:48:34	1.9
+++ libiberty/xmalloc.c	2000/11/20 23:27:46
@@ -24,6 +24,10 @@ Boston, MA 02111-1307, USA.  */
 #include "libiberty.h"
 
 #include <stdio.h>
+#include <errno.h>
+#ifdef NEED_DECLARATION_ERRNO
+extern int errno;
+#endif
 
 #ifdef __STDC__
 #include <stddef.h>
@@ -64,6 +68,36 @@ xmalloc_set_program_name (s)
 #endif /* HAVE_SBRK */
 }
 
+void
+xmalloc_failed (size)
+     size_t size;
+{
+  int save_errno = errno;
+
+#ifdef HAVE_SBRK
+  extern char **environ;
+  size_t allocated;
+
+  if (first_break != NULL)
+    allocated = (char *) sbrk (0) - first_break;
+  else
+    allocated = (char *) sbrk (0) - (char *) &environ;
+  fprintf (stderr,
+	   "\n%s%sCannot allocate %lu bytes after allocating %lu bytes\n",
+	   name, *name ? ": " : "",
+	   (unsigned long) size, (unsigned long) allocated);
+#else /* HAVE_SBRK */
+  fprintf (stderr,
+	   "\n%s%sCannot allocate %lu bytes\n",
+	   name, *name ? ": " : "",
+	   (unsigned long) size);
+#endif /* HAVE_SBRK */
+  fprintf (stderr, "%s%s(%s)\n",
+	   name, *name ? ": " : "", xstrerror (save_errno));
+	   
+  xexit (1);
+}
+
 PTR
 xmalloc (size)
     size_t size;
@@ -73,29 +107,10 @@ xmalloc (size)
   if (size == 0)
     size = 1;
   newmem = malloc (size);
-  if (!newmem)
-    {
-#ifdef HAVE_SBRK
-      extern char **environ;
-      size_t allocated;
+  if (newmem)
+    return (newmem);
 
-      if (first_break != NULL)
-	allocated = (char *) sbrk (0) - first_break;
-      else
-	allocated = (char *) sbrk (0) - (char *) &environ;
-      fprintf (stderr,
-	       "\n%s%sCannot allocate %lu bytes after allocating %lu bytes\n",
-	       name, *name ? ": " : "",
-	       (unsigned long) size, (unsigned long) allocated);
-#else /* HAVE_SBRK */
-      fprintf (stderr,
-              "\n%s%sCannot allocate %lu bytes\n",
-              name, *name ? ": " : "",
-              (unsigned long) size);
-#endif /* HAVE_SBRK */
-      xexit (1);
-    }
-  return (newmem);
+  xmalloc_failed (size);  /* doesn't return */
 }
 
 PTR
@@ -108,29 +123,10 @@ xcalloc (nelem, elsize)
     nelem = elsize = 1;
 
   newmem = calloc (nelem, elsize);
-  if (!newmem)
-    {
-#ifdef HAVE_SBRK
-      extern char **environ;
-      size_t allocated;
+  if (newmem)
+    return (newmem);
 
-      if (first_break != NULL)
-	allocated = (char *) sbrk (0) - first_break;
-      else
-	allocated = (char *) sbrk (0) - (char *) &environ;
-      fprintf (stderr,
-	       "\n%s%sCannot allocate %lu bytes after allocating %lu bytes\n",
-	       name, *name ? ": " : "",
-	       (unsigned long) (nelem * elsize), (unsigned long) allocated);
-#else /* HAVE_SBRK */
-      fprintf (stderr,
-              "\n%s%sCannot allocate %lu bytes\n",
-              name, *name ? ": " : "",
-              (unsigned long) (nelem * elsize));
-#endif /* HAVE_SBRK */
-      xexit (1);
-    }
-  return (newmem);
+  xmalloc_failed (nelem * elsize);  /* doesn't return */
 }
 
 PTR
@@ -146,27 +142,8 @@ xrealloc (oldmem, size)
     newmem = malloc (size);
   else
     newmem = realloc (oldmem, size);
-  if (!newmem)
-    {
-#ifdef HAVE_SBRK
-      extern char **environ;
-      size_t allocated;
+  if (newmem)
+    return (newmem);
 
-      if (first_break != NULL)
-	allocated = (char *) sbrk (0) - first_break;
-      else
-	allocated = (char *) sbrk (0) - (char *) &environ;
-      fprintf (stderr,
-	       "\n%s%sCannot reallocate %lu bytes after allocating %lu bytes\n",
-	       name, *name ? ": " : "",
-	       (unsigned long) size, (unsigned long) allocated);
-#else /* HAVE_SBRK */
-      fprintf (stderr,
-              "\n%s%sCannot reallocate %lu bytes\n",
-              name, *name ? ": " : "",
-              (unsigned long) size);
-#endif /* HAVE_SBRK */
-      xexit (1);
-    }
-  return (newmem);
+  xmalloc_failed (size);  /* doesn't return */
 }
===================================================================
Index: libiberty/xvalloc.c
--- libiberty/xvalloc.c	Tue May  5 13:32:27 1998
+++ libiberty/xvalloc.c	Mon Nov 20 15:27:46 2000
@@ -0,0 +1,293 @@
+/* page-aligned memory allocation routines.
+   Copyright (C) 1999, 2000 Free Software Foundation
+
+This file is part of the libiberty library.
+Libiberty is free software; you can redistribute it and/or
+modify it under the terms of the GNU Library General Public
+License as published by the Free Software Foundation; either
+version 2 of the License, or (at your option) any later version.
+
+Libiberty is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+Library General Public License for more details.
+
+You should have received a copy of the GNU Library General Public
+License along with libiberty; see the file COPYING.LIB.  If not, write
+to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA. */
+
+/* This code allocates page-aligned memory by hook or by crook.
+   If mmap(2) can give us anonymous memory, we use that.  If the
+   system provides valloc(3) or memalign(3), we can use them instead.
+   As a last resort, we use plain malloc, with trickery to extract a
+   page-aligned region from the actual allocation.  */
+
+#if HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <libiberty.h>
+
+#if HAVE_SYS_TYPES_H
+# include <sys/types.h>
+#endif
+#if HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+#if HAVE_UNISTD_H
+# include <unistd.h>
+#endif
+
+#if HAVE_FCNTL_H
+# include <fcntl.h>
+#endif
+
+#if HAVE_SYS_MMAN_H
+# include <sys/mman.h>
+#endif
+
+/* The system's page size.  */
+static size_t pagesize;
+
+/* Test the misalignment of an address.  */
+#define MISALIGNMENT(Address) \
+  (((size_t)(Address)) & (pagesize - 1))
+
+/* Configuration.  */
+
+/* Shut up pedantic warnings about 'inline'. */
+#if defined __GNUC__ && (__GNUC__ >= 3 || __GNUC_MINOR__ >= 7)
+# undef inline
+# define inline __inline__
+#endif
+
+/* For testing */
+#if FORCE_USE_MALLOC
+# undef HAVE_MMAP_ANON
+# undef HAVE_MMAP_DEV_ZERO
+# undef HAVE_VALLOC
+# undef HAVE_POSIX_VALLOC
+# undef HAVE_MEMALIGN
+#endif
+
+#define use_mmap 0
+#define use_valloc 0
+#define use_posix_valloc 0
+#define use_malloc 0
+#define need_dev_zero 0
+
+/* mmap with MAP_ANON(YMOUS) is preferred, because it doesn't require us
+   to hold a file descriptor on /dev/zero.  */
+#ifdef HAVE_MMAP_ANON
+# undef use_mmap
+# define use_mmap 1
+#else
+# ifdef HAVE_MMAP_DEV_ZERO
+#  undef need_dev_zero
+#  define need_dev_zero 1
+#  undef use_mmap
+#  define use_mmap 1
+# else
+/* memalign is preferred to valloc, because valloc may call getpagesize()
+   (which may involve an expensive system call) on every use.  */
+#  ifdef HAVE_MEMALIGN
+#   undef use_valloc
+#   define use_valloc 1
+#   undef valloc
+#   define valloc(size) memalign(pagesize, size)
+#  else
+#   ifdef HAVE_VALLOC
+#    undef use_valloc
+#    define use_valloc 1
+#   else
+#    ifdef HAVE_POSIX_VALLOC
+#     undef use_posix_valloc
+#     define use_posix_valloc 1
+#    else
+#     undef use_malloc
+#     define use_malloc 1
+#    endif
+#   endif
+#  endif
+# endif
+#endif
+
+#if need_dev_zero
+static int dev_zero_fd = -1;
+#else
+#define dev_zero_fd -1
+#endif
+
+#if use_malloc
+static size_t roundup;
+static size_t offset;
+#else
+# define roundup 0
+# define offset 0
+#endif
+
+#ifndef MAP_FAILED
+# define MAP_FAILED -1
+#endif
+#ifndef MAP_ANON
+# ifdef MAP_ANONYMOUS
+#  define MAP_ANON MAP_ANONYMOUS
+# else
+#  define MAP_ANON 0
+# endif
+#endif
+
+/* Sanity check */
+extern int only_one_of_the_use_macros_may_be_nonzero
+[(use_mmap + use_valloc + use_posix_valloc + use_malloc > 1) ? -1 : 1];
+
+static inline char *xv_get_core PARAMS ((size_t));
+static inline void xv_put_core PARAMS ((char *, size_t));
+
+/* Internal allocation/deallocation primitives.  They give you
+   exactly as many bytes as you asked for, with no particular
+   guarantee about how it's aligned; and they expect you to hand
+   back the block just as it was returned by them.  */
+static inline char *
+xv_get_core (size)
+     size_t size;
+{
+#if use_mmap
+  char *res = (char *) mmap (0, size, PROT_READ | PROT_WRITE,
+			     MAP_PRIVATE | MAP_ANON, dev_zero_fd, 0);
+  if (res != (char *) MAP_FAILED)
+    return res;
+
+  return 0;
+#endif
+#if use_valloc
+  return (char *) valloc (size);
+#endif
+#if use_posix_valloc
+  /* POSIX.1d - had to be different... */
+  char *res;
+  int err = posix_valloc (&res, size);
+  if (err == 0)
+    return res;
+
+  errno = err;
+  return 0;
+#endif
+#if use_malloc
+  return (char *) malloc (size);
+#endif
+}
+
+static inline void
+xv_put_core (ptr, size)
+     char *ptr;
+     size_t size ATTRIBUTE_UNUSED;
+{
+#if use_mmap
+  munmap (ptr, size);
+#else
+  /* We assume all other allocation methods permit you to pass the
+     pointer they return to free directly.  This is believed not to be
+     true everywhere, but we were unable to find a platform where it
+     wasn't.  */
+  free (ptr);
+#endif
+}
+
+/* Adjust an allocation request before and after passing it to the
+   underlying allocator, so all higher level code sees an aligned
+   block of memory.  Also traps allocation failures.  */
+char *
+xvalloc (size)
+     size_t size;
+{
+  char *res;
+
+  size += roundup;
+
+  res = xv_get_core (size);
+  if (res == 0)
+    xmalloc_failed (size);	/* doesn't return */
+
+  return res + offset;
+}
+    
+void
+xvfree (ptr, size)
+     char *ptr;
+     size_t size;
+{
+  xv_put_core (ptr - offset, size + roundup);
+}
+
+/* Initialize internal data structures.  */
+void
+xvalloc_init ()
+{
+  pagesize = getpagesize ();
+
+#if need_dev_zero
+  dev_zero_fd = open("/dev/zero", O_RDWR);
+  if (dev_zero_fd == -1)
+    abort ();
+#endif
+
+#if use_mmap
+  /* StunOS has an amazing off-by-one error for the first mmap allocation
+     after fiddling with RLIMIT_STACK.  The result, as hard as it is to
+     believe, is an unaligned page allocation, which would cause us to
+     hork badly if we tried to use it.  */
+  {
+    char *p = xvalloc (pagesize);
+
+    if (MISALIGNMENT (p))
+      {
+       /* How losing.  Discard this one and try another.  If we still
+          can't get something useful, give up.  */
+
+       p = xvalloc (pagesize);
+       if (MISALIGNMENT (p))
+         abort ();
+      }
+    xvfree (p, pagesize);
+  }
+#endif
+
+#if use_malloc
+  /* We must determine how to get page-aligned memory out of this
+     system's malloc implementation.  */
+  {
+    char *p = xvalloc (pagesize);
+    size_t i;
+
+    if (MISALIGNMENT (p) == 0)
+      {
+	/* This malloc page-aligns page-sized memory.  We assume it does
+	   so for all larger allocations as well.  */
+	xvfree (p, pagesize);
+	return;
+      }
+
+    /* Determine the smallest allocation such that there is a complete
+       aligned page within it.  This must happen when we allocate two
+       full pages, but not necessarily before.  */
+    for (i = pagesize + sizeof(int); i <= pagesize*2; i += sizeof(int))
+      {
+	p = xvalloc (i);
+	if (p + pagesize + (pagesize - MISALIGNMENT (p)) <= p + i)
+	  {
+	    size_t r = i - pagesize;
+	    size_t o = pagesize - MISALIGNMENT (p);
+
+	    xvfree (p, i);
+	    roundup = r;
+	    offset = o;
+	    return;
+	  }
+	xvfree (p, i);
+      }
+    abort ();
+  }
+#endif
+}

--
Want to unsubscribe from this list?
Send a message to [email-masked]