Use mmap(2) emulation for buffer text on MS-Windows.
authorFabrice Popineau <fabrice.popineau@gmail.com>
Tue, 27 May 2014 17:31:17 +0000 (20:31 +0300)
committerEli Zaretskii <eliz@gnu.org>
Tue, 27 May 2014 17:31:17 +0000 (20:31 +0300)
 src/Makefile.in (C_HEAP_SWITCH): Get the predefined heap size from
 configure.
 (ADDSECTION, MINGW_TEMACS_POST_LINK): Remove, no longer used.
 src/lisp.h (NONPOINTER_BITS): Modify the condition to define to zero
 for MinGW, since it no longer uses gmalloc.
 src/buffer.c: Do not define mmap allocations functions for Windows.
 Remove mmap_find which is unused. Remove mmap_set_vars which does
 nothing useful.
 [WINDOWSNT]: Include w32heap.h.
 (init_buffer): Always allocate new memory for buffers.
 src/emacs.c: Remove mmap_set_vars calls.
 src/image.c (free_image): Undef free for Windows because it is
 redirected to our private version.
 src/unexw32.c (COPY_PROC_CHUNK): Use %p format for 64bits
 compatibility.
 (copy_executable_and_dump_data): Remove dumping the heap section.
 (unexec): Restore using_dynamic_heap after dumping.
 src/w32heap.c (dumped_data_commit, malloc_after_dump)
 (malloc_before_dump, realloc_after_dump, realloc_before_dump)
 (free_after_dump, free_before_dump, mmap_alloc, mmap_realloc)
 (mmap_free): New functions.
 src/w32heap.h: Declare dumped_data and mmap_* function prototypes.

 nt/inc/ms-w32.h: Switch to the system heap allocation scheme
 instead of GNU malloc and ralloc.
 nt/inc/sys/mman.h: New file.
 nt/INSTALL: Update for the new build requirements.

 etc/NEWS: Mention build changes on MS-Windows.

 configure.ac (C_HEAP_SWITCH) define for different values of
 dumped heap size depending on 32/64bits arch on Windows.
 Don't check for pthreads.h on MinGW32/64, it gets in the way.
 Use mmap(2) for buffers and system malloc for MinGW32/64.

17 files changed:
ChangeLog
configure.ac
etc/ChangeLog
etc/NEWS
nt/ChangeLog
nt/INSTALL
nt/inc/ms-w32.h
nt/inc/sys/mman.h [new file with mode: 0644]
src/ChangeLog
src/Makefile.in
src/buffer.c
src/emacs.c
src/image.c
src/lisp.h
src/unexw32.c
src/w32heap.c
src/w32heap.h

index 28c877a..09f0618 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,10 @@
+2014-05-27  Fabrice Popineau  <fabrice.popineau@gmail.com>
+
+       * configure.ac (C_HEAP_SWITCH) define for different values of
+       dumped heap size depending on 32/64bits arch on Windows.
+       Don't check for pthreads.h on MinGW32/64, it gets in the way.
+       Use mmap(2) for buffers and system malloc for MinGW32/64.
+
 2014-05-27  Paul Eggert  <eggert@cs.ucla.edu>
 
        Merge from gnulib, incorporating:
index d727c02..84f989f 100644 (file)
@@ -1973,7 +1973,7 @@ doug_lea_malloc=$emacs_cv_var_doug_lea_malloc
 system_malloc=$emacs_cv_sanitize_address
 case "$opsys" in
   ## darwin ld insists on the use of malloc routines in the System framework.
-  darwin|sol2-10) system_malloc=yes ;;
+  darwin|mingw32|sol2-10) system_malloc=yes ;;
 esac
 
 GMALLOC_OBJ=
@@ -2020,7 +2020,7 @@ if test "$doug_lea_malloc" = "yes" ; then
   ## #ifdef DOUG_LEA_MALLOC; #undef REL_ALLOC; #endif
   ## Does the AC_FUNC_MMAP test below make this check unnecessary?
   case "$opsys" in
-    gnu*) REL_ALLOC=no ;;
+    mingw32|gnu*) REL_ALLOC=no ;;
   esac
 fi
 
@@ -2030,7 +2030,7 @@ fi
 
 use_mmap_for_buffers=no
 case "$opsys" in
-  cygwin|freebsd|irix6-5) use_mmap_for_buffers=yes ;;
+  cygwin|mingw32|freebsd|irix6-5) use_mmap_for_buffers=yes ;;
 esac
 
 AC_FUNC_MMAP
@@ -2046,6 +2046,7 @@ AC_CHECK_LIB(Xbsd, main, LD_SWITCH_X_SITE="$LD_SWITCH_X_SITE -lXbsd")
 
 dnl Check for the POSIX thread library.
 LIB_PTHREAD=
+if test "$opsys" != "mingw32"; then
 AC_CHECK_HEADERS_ONCE(pthread.h)
 if test "$ac_cv_header_pthread_h"; then
   dnl gmalloc.c uses pthread_atfork, which is not available on older-style
@@ -2066,6 +2067,7 @@ if test "$ac_cv_header_pthread_h"; then
   LIBS=$OLD_LIBS
 fi
 AC_SUBST([LIB_PTHREAD])
+fi
 
 dnl Check for need for bigtoc support on IBM AIX
 
@@ -4817,11 +4819,9 @@ case "$opsys" in
   gnu*) LD_SWITCH_SYSTEM_TEMACS="\$(LD_SWITCH_X_SITE_RPATH)" ;;
 
   mingw32)
-   ## MinGW64 does not prepend an underscore to symbols, so we must
-   ## pass a different -entry switch to linker.  FIXME: It is better
-   ## to make the entry points the same by changing unexw32.c.
+   ## Is it any better under MinGW64 to relocate emacs into higher addresses?
    case "$canonical" in
-     x86_64-*-*) LD_SWITCH_SYSTEM_TEMACS="-Wl,-stack,0x00800000 -Wl,-heap,0x00100000 -Wl,-image-base,0x01000000 -Wl,-entry,__start -Wl,-Map,./temacs.map" ;;
+     x86_64-*-*) LD_SWITCH_SYSTEM_TEMACS="-Wl,-stack,0x00800000 -Wl,-heap,0x00100000 -Wl,-image-base,0x400000000 -Wl,-entry,__start -Wl,-Map,./temacs.map" ;;
      *) LD_SWITCH_SYSTEM_TEMACS="-Wl,-stack,0x00800000 -Wl,-heap,0x00100000 -Wl,-image-base,0x01000000 -Wl,-entry,__start -Wl,-Map,./temacs.map" ;;
    esac
    ;;
@@ -4845,20 +4845,20 @@ AC_SUBST(LD_SWITCH_SYSTEM_TEMACS)
 ## MinGW-specific post-link processing of temacs.
 TEMACS_POST_LINK=":"
 ADDSECTION=
-EMACS_HEAPSIZE=
+C_HEAP_SWITCH=
 if test "${opsys}" = "mingw32"; then
   TEMACS_POST_LINK="\$(MINGW_TEMACS_POST_LINK)"
   ADDSECTION="../nt/addsection\$(EXEEXT)"
   ## Preload heap size of temacs.exe in MB.
   case "$canonical" in
-    x86_64-*-*) EMACS_HEAPSIZE=42 ;;
-    *) EMACS_HEAPSIZE=27 ;;
+    x86_64-*-*) C_HEAP_SWITCH="-DHEAPSIZE=18" ;;
+    *) C_HEAP_SWITCH="-DHEAPSIZE=10" ;;
   esac
 fi
 
 AC_SUBST(ADDSECTION)
 AC_SUBST(TEMACS_POST_LINK)
-AC_SUBST(EMACS_HEAPSIZE)
+AC_SUBST(C_HEAP_SWITCH)
 
 ## Common for all window systems
 if test "$window_system" != "none"; then
index 49be20a..27ee804 100644 (file)
@@ -1,3 +1,7 @@
+2014-05-27  Fabrice Popineau  <fabrice.popineau@gmail.com>
+
+       * NEWS: Mention build changes on MS-Windows.
+
 2014-05-26  Paul Eggert  <eggert@cs.ucla.edu>
 
        Specify coding if Latin-1 Emacs would misinterpret (Bug#17575).
index 3d76642..2011245 100644 (file)
--- a/etc/NEWS
+++ b/etc/NEWS
@@ -40,6 +40,11 @@ or by sticking with Emacs 24.4.
 ** The configure option `--with-pkg-config-prog' has been removed.
 Use './configure PKG_CONFIG=/full/name/of/pkg-config' if you need to.
 
+---
+** Building Emacs for MS-Windows requires at least Windows XP
+or Windows Server 2003.  The built binaries still run on all versions
+of Windows starting with Windows 9X.
+
 \f
 * Startup Changes in Emacs 24.5
 
index a3cb5e6..961de32 100644 (file)
@@ -1,3 +1,12 @@
+2014-05-27  Fabrice Popineau  <fabrice.popineau@gmail.com>
+
+       * inc/ms-w32.h: Switch to the system heap allocation scheme
+       instead of GNU malloc and ralloc.
+
+       * inc/sys/mman.h: New file.
+
+       * INSTALL: Update for the new build requirements.
+
 2014-05-17  Paul Eggert  <eggert@cs.ucla.edu>
 
        Assume C99 or later (Bug#17487).
index 949a4e4..4ecf4da 100644 (file)
@@ -5,9 +5,9 @@
   See the end of the file for license conditions.
 
 The MSYS/MinGW build described here is supported on versions of
-Windows starting with Windows 2000 and newer.  Windows 9X are not
-supported (but the Emacs binary produced by this build will run on
-Windows 9X as well).
+Windows starting with Windows XP and newer.  Building on Windows 2000
+and Windows 9X is not supported (but the Emacs binary produced by this
+build will run on Windows 9X and newer systems).
 
   Do not use this recipe with Cygwin.  For building on Cygwin, use the
   normal installation instructions, ../INSTALL.
@@ -389,9 +389,10 @@ Windows 9X as well).
 
        Where should the build process find the source code?    /path/to/emacs/sources
        What compiler should emacs be built with?               gcc  -std=gnu99 -O0 -g3
-       Should Emacs use the GNU version of malloc?             yes
-       Should Emacs use a relocating allocator for buffers?    yes
-       Should Emacs use mmap(2) for buffer allocation?         no
+       Should Emacs use the GNU version of malloc?             no
+        (The GNU allocators don't work with this system configuration.)
+       Should Emacs use a relocating allocator for buffers?    no
+       Should Emacs use mmap(2) for buffer allocation?         yes
        What window system should Emacs use?                    w32
        What toolkit should Emacs use?                          none
        Where do we find X Windows header files?                NONE
@@ -401,13 +402,16 @@ Windows 9X as well).
        Does Emacs use -ljpeg?                                  yes
        Does Emacs use -ltiff?                                  yes
        Does Emacs use a gif library?                           yes
-       Does Emacs use -lpng?                                   yes
-       Does Emacs use -lrsvg-2?                                no
+       Does Emacs use a png library?                           yes
+       Does Emacs use -lrsvg-2?                                yes
        Does Emacs use imagemagick?                             no
+       Does Emacs support sound?                               no
        Does Emacs use -lgpm?                                   no
        Does Emacs use -ldbus?                                  no
        Does Emacs use -lgconf?                                 no
        Does Emacs use GSettings?                               no
+       Does Emacs use a file notification library?             yes (w32)
+       Does Emacs use access control lists?                    yes
        Does Emacs use -lselinux?                               no
        Does Emacs use -lgnutls?                                yes
        Does Emacs use -lxml2?                                  yes
@@ -415,6 +419,7 @@ Windows 9X as well).
        Does Emacs use -lm17n-flt?                              no
        Does Emacs use -lotf?                                   no
        Does Emacs use -lxft?                                   no
+       Does Emacs directly use zlib?                           yes
        Does Emacs use toolkit scroll bars?                     yes
 
   You are almost there, hang on.
index 8f7c36a..1cf78ba 100644 (file)
@@ -140,6 +140,7 @@ extern char *getenv ();
    in its system headers, and is not really compatible with values
    lower than 0x0500, so leave it alone.  */
 #ifndef _W64
+# undef _WIN32_WINNT
 # define _WIN32_WINNT 0x0400
 #endif
 
@@ -427,20 +428,36 @@ extern char *get_emacs_configuration_options (void);
 #define _WINSOCK_H
 
 /* Defines size_t and alloca ().  */
-#ifdef emacs
-#define malloc e_malloc
-#define free   e_free
-#define realloc e_realloc
-#define calloc e_calloc
-#endif
+#include <stdlib.h>
+#include <sys/stat.h>
 #ifdef _MSC_VER
 #define alloca _alloca
 #else
 #include <malloc.h>
 #endif
 
-#include <stdlib.h>
-#include <sys/stat.h>
+#ifdef emacs
+
+typedef void * (* malloc_fn)(size_t);
+typedef void * (* realloc_fn)(void *, size_t);
+typedef void (* free_fn)(void *);
+
+extern void *malloc_before_dump(size_t);
+extern void *realloc_before_dump(void *, size_t);
+extern void free_before_dump(void *);
+extern void *malloc_after_dump(size_t);
+extern void *realloc_after_dump(void *, size_t);
+extern void free_after_dump(void *);
+
+extern malloc_fn the_malloc_fn;
+extern realloc_fn the_realloc_fn;
+extern free_fn the_free_fn;
+
+#define malloc(size) (*the_malloc_fn)(size)
+#define free(ptr)   (*the_free_fn)(ptr)
+#define realloc(ptr, size) (*the_realloc_fn)(ptr, size)
+
+#endif
 
 /* Define for those source files that do not include enough NT system files.  */
 #ifndef NULL
diff --git a/nt/inc/sys/mman.h b/nt/inc/sys/mman.h
new file mode 100644 (file)
index 0000000..6990edc
--- /dev/null
@@ -0,0 +1,31 @@
+/*
+ * sys/mman.h
+ * mman-win32
+ */
+
+#ifndef _SYS_MMAN_H_
+#define _SYS_MMAN_H_
+
+#include <sys/types.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* We need MAP_ANON in src/buffer.c */
+
+#define MAP_FILE        0
+#define MAP_SHARED      1
+#define MAP_PRIVATE     2
+#define MAP_TYPE        0xf
+#define MAP_FIXED       0x10
+#define MAP_ANONYMOUS   0x20
+#define MAP_ANON        MAP_ANONYMOUS
+
+#define MAP_FAILED      ((void *)-1)
+
+#ifdef __cplusplus
+};
+#endif
+
+#endif /*  _SYS_MMAN_H_ */
index 4378cfc..959f29a 100644 (file)
@@ -1,3 +1,35 @@
+2014-05-27  Fabrice Popineau  <fabrice.popineau@gmail.com>
+
+       * Makefile.in (C_HEAP_SWITCH): Get the predefined heap size from
+       configure.
+       (ADDSECTION, MINGW_TEMACS_POST_LINK): Remove, no longer used.
+
+       * lisp.h (NONPOINTER_BITS): Modify the condition to define to zero
+       for MinGW, since it no longer uses gmalloc.
+
+       * buffer.c: Do not define mmap allocations functions for Windows.
+       Remove mmap_find which is unused. Remove mmap_set_vars which does
+       nothing useful.
+       [WINDOWSNT]: Include w32heap.h.
+       (init_buffer): Always allocate new memory for buffers.
+
+       * emacs.c: Remove mmap_set_vars calls.
+
+       * image.c (free_image): Undef free for Windows because it is
+       redirected to our private version.
+
+       * unexw32.c (COPY_PROC_CHUNK): Use %p format for 64bits
+       compatibility.
+       (copy_executable_and_dump_data): Remove dumping the heap section.
+       (unexec): Restore using_dynamic_heap after dumping.
+
+       * w32heap.c (dumped_data_commit, malloc_after_dump)
+       (malloc_before_dump, realloc_after_dump, realloc_before_dump)
+       (free_after_dump, free_before_dump, mmap_alloc, mmap_realloc)
+       (mmap_free): New functions.
+
+       * w32heap.h: Declare dumped_data and mmap_* function prototypes.
+
 2014-05-27  Paul Eggert  <eggert@cs.ucla.edu>
 
        * image.c (imagemagick_load_image): Use MagickRealType for local
index b4e9eae..0f4130b 100644 (file)
@@ -86,6 +86,9 @@ PNG_CFLAGS=@PNG_CFLAGS@
 ## something similar.  This is normally set by configure.
 C_SWITCH_X_SITE=@C_SWITCH_X_SITE@
 
+## Set Emacs dumped heap size for Windows NT
+C_HEAP_SWITCH=@C_HEAP_SWITCH@
+
 ## Define LD_SWITCH_X_SITE to contain any special flags your loader
 ## may need to deal with X Windows.  For instance, if your X libraries
 ## aren't in a place that your loader can find on its own, you might
@@ -300,11 +303,7 @@ RUN_TEMACS = ./temacs
 
 ## Invoke ../nt/addsection for MinGW, ":" elsewhere.
 TEMACS_POST_LINK = @TEMACS_POST_LINK@
-ADDSECTION = @ADDSECTION@
 EMACS_HEAPSIZE = @EMACS_HEAPSIZE@
-MINGW_TEMACS_POST_LINK = \
- mv temacs$(EXEEXT) temacs.tmp; \
- ../nt/addsection temacs.tmp temacs$(EXEEXT) EMHEAP $(EMACS_HEAPSIZE)
 
 UNEXEC_OBJ = @UNEXEC_OBJ@
 
@@ -326,7 +325,7 @@ MKDEPDIR=@MKDEPDIR@
 ##
 ## FIXME? MYCPPFLAGS only referenced in etc/DEBUG.
 ALL_CFLAGS=-Demacs $(MYCPPFLAGS) -I. -I$(srcdir) \
-  -I$(lib) -I$(srcdir)/../lib \
+  -I$(lib) -I$(srcdir)/../lib $(C_HEAP_SWITCH) \
   $(C_SWITCH_MACHINE) $(C_SWITCH_SYSTEM) $(C_SWITCH_X_SITE) \
   $(GNUSTEP_CFLAGS) $(CFLAGS_SOUND) $(RSVG_CFLAGS) $(IMAGEMAGICK_CFLAGS) \
   $(PNG_CFLAGS) $(LIBXML2_CFLAGS) $(DBUS_CFLAGS) \
index 1f0bd3f..3cbb815 100644 (file)
@@ -41,6 +41,10 @@ along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.  */
 #include "keymap.h"
 #include "frame.h"
 
+#ifdef WINDOWSNT
+#include "w32heap.h"           /* for mmap_* */
+#endif
+
 struct buffer *current_buffer;         /* The current buffer.  */
 
 /* First buffer in chain of all buffers (in reverse order of creation).
@@ -4632,7 +4636,8 @@ evaporate_overlays (ptrdiff_t pos)
                         Allocation with mmap
  ***********************************************************************/
 
-#ifdef USE_MMAP_FOR_BUFFERS
+/* Note: WINDOWSNT implements this stuff on w32heap.c.  */
+#if defined USE_MMAP_FOR_BUFFERS && !defined WINDOWSNT
 
 #include <sys/mman.h>
 
@@ -4774,36 +4779,6 @@ mmap_init (void)
   mmap_page_size = getpagesize ();
 }
 
-/* Return a region overlapping address range START...END, or null if
-   none.  END is not including, i.e. the last byte in the range
-   is at END - 1.  */
-
-static struct mmap_region *
-mmap_find (void *start, void *end)
-{
-  struct mmap_region *r;
-  char *s = start, *e = end;
-
-  for (r = mmap_regions; r; r = r->next)
-    {
-      char *rstart = (char *) r;
-      char *rend   = rstart + r->nbytes_mapped;
-
-      if (/* First byte of range, i.e. START, in this region?  */
-         (s >= rstart && s < rend)
-         /* Last byte of range, i.e. END - 1, in this region?  */
-         || (e > rstart && e <= rend)
-         /* First byte of this region in the range?  */
-         || (rstart >= s && rstart < e)
-         /* Last byte of this region in the range?  */
-         || (rend > s && rend <= e))
-       break;
-    }
-
-  return r;
-}
-
-
 /* Unmap a region.  P is a pointer to the start of the user-araa of
    the region.  */
 
@@ -4880,38 +4855,6 @@ mmap_enlarge (struct mmap_region *r, int npages)
 }
 
 
-/* Set or reset variables holding references to mapped regions.
-   If not RESTORE_P, set all variables to null.  If RESTORE_P, set all
-   variables to the start of the user-areas of mapped regions.
-
-   This function is called from Fdump_emacs to ensure that the dumped
-   Emacs doesn't contain references to memory that won't be mapped
-   when Emacs starts.  */
-
-void
-mmap_set_vars (bool restore_p)
-{
-  struct mmap_region *r;
-
-  if (restore_p)
-    {
-      mmap_regions = mmap_regions_1;
-      mmap_fd = mmap_fd_1;
-      for (r = mmap_regions; r; r = r->next)
-       *r->var = MMAP_USER_AREA (r);
-    }
-  else
-    {
-      for (r = mmap_regions; r; r = r->next)
-       *r->var = NULL;
-      mmap_regions_1 = mmap_regions;
-      mmap_regions = NULL;
-      mmap_fd_1 = mmap_fd;
-      mmap_fd = -1;
-    }
-}
-
-
 /* Allocate a block of storage large enough to hold NBYTES bytes of
    data.  A pointer to the data is returned in *VAR.  VAR is thus the
    address of some variable which will use the data area.
index 16d91de..fabea11 100644 (file)
@@ -2155,13 +2155,8 @@ You must run Emacs in batch mode in order to dump it.  */)
   malloc_state_ptr = malloc_get_state ();
 #endif
 
-#ifdef USE_MMAP_FOR_BUFFERS
-  mmap_set_vars (0);
-#endif
   unexec (SSDATA (filename), !NILP (symfile) ? SSDATA (symfile) : 0);
-#ifdef USE_MMAP_FOR_BUFFERS
-  mmap_set_vars (1);
-#endif
+
 #ifdef DOUG_LEA_MALLOC
   free (malloc_state_ptr);
 #endif
index 07cf9f9..304603e 100644 (file)
@@ -998,6 +998,11 @@ free_image (struct frame *f, struct image *img)
 
       c->images[img->id] = NULL;
 
+      /* Windows NT redefines 'free', but in this file, we need to
+         avoid the redefinition.  */
+#ifdef WINDOWSNT
+#undef free
+#endif
       /* Free resources, then free IMG.  */
       img->type->free (f, img);
       xfree (img);
@@ -6453,7 +6458,6 @@ jpeg_file_src (j_decompress_ptr cinfo, FILE *fp)
   src->mgr.next_input_byte = NULL;
 }
 
-
 /* Load image IMG for use on frame F.  Patterned after example.c
    from the JPEG lib.  */
 
index 2fd2835..62fca16 100644 (file)
@@ -72,7 +72,7 @@ DEFINE_GDB_SYMBOL_END (GCTYPEBITS)
    2.  We know malloc returns a multiple of 8.  */
 #if (defined alignas \
      && (defined GNU_MALLOC || defined DOUG_LEA_MALLOC || defined __GLIBC__ \
-        || defined DARWIN_OS || defined __sun))
+        || defined DARWIN_OS || defined __sun || defined __MINGW32__))
 # define NONPOINTER_BITS 0
 #else
 # define NONPOINTER_BITS GCTYPEBITS
index f70cdd7..60b926b 100644 (file)
@@ -83,8 +83,6 @@ PCHAR  bss_start_static = 0;
 DWORD_PTR  bss_size_static = 0;
 DWORD_PTR  extra_bss_size_static = 0;
 
-PIMAGE_SECTION_HEADER heap_section;
-
 /* MinGW64 doesn't add a leading underscore to external symbols,
    whereas configure.ac sets up LD_SWITCH_SYSTEM_TEMACS to force the
    entry point at __start, with two underscores.  */
@@ -475,8 +473,6 @@ get_section_info (file_data *p_infile)
       bss_section_static = 0;
       extra_bss_size_static = 0;
     }
-
-  heap_section = rva_to_section (PTR_TO_RVA (get_heap_start ()), nt_header);
 }
 
 
@@ -518,9 +514,11 @@ copy_executable_and_dump_data (file_data *p_infile,
     if (verbose)                                                               \
       {                                                                                \
        printf ("%s\n", (message));                                             \
-       printf ("\t0x%08x Address in process.\n", s);                           \
-       printf ("\t0x%08x Offset in output file.\n", dst - p_outfile->file_base); \
-       printf ("\t0x%08x Size in bytes.\n", count);                            \
+       printf ("\t0x%p Address in process.\n", s);                             \
+       printf ("\t0x%p Base       output file.\n", p_outfile->file_base); \
+       printf ("\t0x%p Offset  in output file.\n", dst - p_outfile->file_base); \
+       printf ("\t0x%p Address in output file.\n", dst); \
+       printf ("\t0x%p Size in bytes.\n", count);                              \
       }                                                                                \
     memcpy (dst, s, count);                                                    \
     dst += count;                                                              \
@@ -629,34 +627,6 @@ copy_executable_and_dump_data (file_data *p_infile,
          dst_section->Characteristics &= ~IMAGE_SCN_CNT_UNINITIALIZED_DATA;
          dst_section->Characteristics |= IMAGE_SCN_CNT_INITIALIZED_DATA;
        }
-      if (section == heap_section)
-       {
-         DWORD_PTR heap_start = (DWORD_PTR) get_heap_start ();
-         DWORD_PTR heap_size = get_committed_heap_size ();
-
-         /* Dump the used portion of the predump heap, adjusting the
-             section's size to the appropriate size.  */
-         dst = dst_save
-           + RVA_TO_SECTION_OFFSET (PTR_TO_RVA (heap_start), dst_section);
-         COPY_PROC_CHUNK ("Dumping heap...", heap_start, heap_size,
-                          be_verbose);
-         ROUND_UP_DST (dst_nt_header->OptionalHeader.FileAlignment);
-         dst_section->PointerToRawData = PTR_TO_OFFSET (dst_save, p_outfile);
-         /* Determine new size of raw data area.  */
-         dst = max (dst, dst_save + dst_section->SizeOfRawData);
-         dst_section->SizeOfRawData = dst - dst_save;
-         /* Reduce the size of the heap section to fit (must be last
-             section).  */
-         dst_nt_header->OptionalHeader.SizeOfImage -=
-           dst_section->Misc.VirtualSize
-           - ROUND_UP (dst_section->SizeOfRawData,
-                       dst_nt_header->OptionalHeader.SectionAlignment);
-         dst_section->Misc.VirtualSize =
-           ROUND_UP (dst_section->SizeOfRawData,
-                     dst_nt_header->OptionalHeader.SectionAlignment);
-         dst_section->Characteristics &= ~IMAGE_SCN_CNT_UNINITIALIZED_DATA;
-         dst_section->Characteristics |= IMAGE_SCN_CNT_INITIALIZED_DATA;
-       }
 
       /* Align the section's raw data area.  */
       ROUND_UP_DST (dst_nt_header->OptionalHeader.FileAlignment);
@@ -767,9 +737,6 @@ unexec (const char *new_name, const char *old_name)
   printf ("Dumping from %s\n", in_filename);
   printf ("          to %s\n", out_filename);
 
-  /* We need to round off our heap to NT's page size.  */
-  round_heap (get_page_size ());
-
   /* Open the undumped executable file.  */
   if (!open_input_file (&in_file, in_filename))
     {
@@ -784,7 +751,6 @@ unexec (const char *new_name, const char *old_name)
   /* The size of the dumped executable is the size of the original
      executable plus the size of the heap and the size of the .bss section.  */
   size = in_file.size +
-    get_committed_heap_size () +
     extra_bss_size +
     extra_bss_size_static;
   if (!open_output_file (&out_file, out_filename, size))
@@ -799,6 +765,10 @@ unexec (const char *new_name, const char *old_name)
 
   copy_executable_and_dump_data (&in_file, &out_file);
 
+  /* Unset it because it is plain wrong to keep it after dumping.
+     Malloc can still occur!  */
+  using_dynamic_heap = FALSE;
+
   /* Patch up header fields; profiler is picky about this. */
   {
     PIMAGE_DOS_HEADER dos_header;
dissimilarity index 88%
index 8ab2f58..7cce7c5 100644 (file)
-/* Heap management routines for GNU Emacs on the Microsoft Windows API.
-   Copyright (C) 1994, 2001-2014 Free Software Foundation, Inc.
-
-This file is part of GNU Emacs.
-
-GNU Emacs is free software: you can redistribute it and/or modify
-it under the terms of the GNU General Public License as published by
-the Free Software Foundation, either version 3 of the License, or
-(at your option) any later version.
-
-GNU Emacs 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 General Public License for more details.
-
-You should have received a copy of the GNU General Public License
-along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.  */
-
-/*
-   Geoff Voelker (voelker@cs.washington.edu)                        7-29-94
-*/
-
-#include <config.h>
-#include <stdio.h>
-
-#include "w32common.h"
-#include "w32heap.h"
-#include "lisp.h"  /* for VALMASK */
-
-#define RVA_TO_PTR(rva) ((unsigned char *)((DWORD_PTR)(rva) + (DWORD_PTR)GetModuleHandle (NULL)))
-
-/* Emulate getpagesize.  */
-int
-getpagesize (void)
-{
-  return sysinfo_cache.dwPageSize;
-}
-
-/* Info for managing our preload heap, which is essentially a fixed size
-   data area in the executable.  */
-PIMAGE_SECTION_HEADER preload_heap_section;
-
-/* Info for keeping track of our heap.  */
-unsigned char *data_region_base = NULL;
-unsigned char *data_region_end = NULL;
-unsigned char *real_data_region_end = NULL;
-size_t  reserved_heap_size = 0;
-
-/* The start of the data segment.  */
-unsigned char *
-get_data_start (void)
-{
-  return data_region_base;
-}
-
-/* The end of the data segment.  */
-unsigned char *
-get_data_end (void)
-{
-  return data_region_end;
-}
-
-#if !USE_LSB_TAG
-static char *
-allocate_heap (void)
-{
-  /* Try to get as much as possible of the address range from the end of
-     the preload heap section up to the usable address limit.  Since GNU
-     malloc can handle gaps in the memory it gets from sbrk, we can
-     simply set the sbrk pointer to the base of the new heap region.  */
-  DWORD_PTR base =
-    ROUND_UP ((RVA_TO_PTR (preload_heap_section->VirtualAddress)
-              + preload_heap_section->Misc.VirtualSize),
-             get_allocation_unit ());
-  DWORD_PTR end  = ((unsigned __int64)1) << VALBITS; /* 256MB */
-  void *ptr = NULL;
-
-  while (!ptr && (base < end))
-    {
-#ifdef _WIN64
-      reserved_heap_size = min(end - base, 0x4000000000ull); /* Limit to 256Gb */
-#else
-      reserved_heap_size = end - base;
-#endif
-      ptr = VirtualAlloc ((void *) base,
-                         get_reserved_heap_size (),
-                         MEM_RESERVE,
-                         PAGE_NOACCESS);
-      base += 0x00100000;  /* 1MB increment */
-    }
-
-  return ptr;
-}
-#else  /* USE_LSB_TAG */
-static char *
-allocate_heap (void)
-{
-#ifdef _WIN64
-  size_t size = 0x4000000000ull; /* start by asking for 32GB */
-#else
-  /* We used to start with 2GB here, but on Windows 7 that would leave
-     too little room in the address space for threads started by
-     Windows on our behalf, e.g. when we pop up the file selection
-     dialog.  */
-  size_t size = 0x68000000; /* start by asking for 1.7GB */
-#endif
-  void *ptr = NULL;
-
-  while (!ptr && size > 0x00100000)
-    {
-      reserved_heap_size = size;
-      ptr = VirtualAlloc (NULL,
-                         get_reserved_heap_size (),
-                         MEM_RESERVE,
-                         PAGE_NOACCESS);
-      size -= 0x00800000; /* if failed, decrease request by 8MB */
-    }
-
-  return ptr;
-}
-#endif /* USE_LSB_TAG */
-
-
-/* Emulate Unix sbrk.  Note that ralloc.c expects the return value to
-   be the address of the _start_ (not end) of the new block in case of
-   success, and zero (not -1) in case of failure.  */
-void *
-sbrk (ptrdiff_t increment)
-{
-  void *result;
-  ptrdiff_t size = increment;
-
-  result = data_region_end;
-
-  /* If size is negative, shrink the heap by decommitting pages.  */
-  if (size < 0)
-    {
-      ptrdiff_t new_size;
-      unsigned char *new_data_region_end;
-
-      size = -size;
-
-      /* Sanity checks.  */
-      if ((data_region_end - size) < data_region_base)
-       return NULL;
-
-      /* We can only decommit full pages, so allow for
-        partial deallocation [cga].  */
-      new_data_region_end = (data_region_end - size);
-      new_data_region_end = (unsigned char *)
-       ((DWORD_PTR) (new_data_region_end + syspage_mask) & ~syspage_mask);
-      new_size = real_data_region_end - new_data_region_end;
-      real_data_region_end = new_data_region_end;
-      if (new_size > 0)
-       {
-         /* Decommit size bytes from the end of the heap.  */
-         if (using_dynamic_heap
-             && !VirtualFree (real_data_region_end, new_size, MEM_DECOMMIT))
-           return NULL;
-       }
-
-      data_region_end -= size;
-    }
-  /* If size is positive, grow the heap by committing reserved pages.  */
-  else if (size > 0)
-    {
-      /* Sanity checks.  */
-      if ((data_region_end + size) >
-         (data_region_base + get_reserved_heap_size ()))
-       return NULL;
-
-      /* Commit more of our heap. */
-      if (using_dynamic_heap
-         && VirtualAlloc (data_region_end, size, MEM_COMMIT,
-                          PAGE_READWRITE) == NULL)
-       return NULL;
-      data_region_end += size;
-
-      /* We really only commit full pages, so record where
-        the real end of committed memory is [cga].  */
-      real_data_region_end = (unsigned char *)
-         ((DWORD_PTR) (data_region_end + syspage_mask) & ~syspage_mask);
-    }
-
-  return result;
-}
-
-/* Initialize the internal heap variables used by sbrk.  When running in
-   preload phase (ie. in the undumped executable), we rely entirely on a
-   fixed size heap section included in the .exe itself; this is
-   preserved during dumping, and truncated to the size actually used.
-
-   When running in the dumped executable, we reserve as much as possible
-   of the address range that is addressable by Lisp object pointers, to
-   supplement what is left of the preload heap.  Although we cannot rely
-   on the dynamically allocated arena being contiguous with the static
-   heap area, it is not a problem because sbrk can pretend that the gap
-   was allocated by something else; GNU malloc detects when there is a
-   jump in the sbrk values, and starts a new heap block.  */
-void
-init_heap (void)
-{
-  PIMAGE_DOS_HEADER dos_header;
-  PIMAGE_NT_HEADERS nt_header;
-
-  dos_header = (PIMAGE_DOS_HEADER) RVA_TO_PTR (0);
-  nt_header = (PIMAGE_NT_HEADERS) (((DWORD_PTR) dos_header) +
-                                  dos_header->e_lfanew);
-  preload_heap_section = find_section ("EMHEAP", nt_header);
-
-  if (using_dynamic_heap)
-    {
-      data_region_base = allocate_heap ();
-      if (!data_region_base)
-       {
-         printf ("Error: Could not reserve dynamic heap area.\n");
-         exit (1);
-       }
-
-#if !USE_LSB_TAG
-      /* Ensure that the addresses don't use the upper tag bits since
-        the Lisp type goes there.  */
-      if (((DWORD_PTR) data_region_base & ~VALMASK) != 0)
-       {
-         printf ("Error: The heap was allocated in upper memory.\n");
-         exit (1);
-       }
-#endif
-      data_region_end = data_region_base;
-      real_data_region_end = data_region_end;
-    }
-  else
-    {
-      data_region_base = RVA_TO_PTR (preload_heap_section->VirtualAddress);
-      data_region_end = data_region_base;
-      real_data_region_end = data_region_end;
-      reserved_heap_size = preload_heap_section->Misc.VirtualSize;
-    }
-
-  /* Update system version information to match current system.  */
-  cache_system_info ();
-}
-
-/* Round the heap up to the given alignment.  */
-void
-round_heap (size_t align)
-{
-  DWORD_PTR needs_to_be;
-  DWORD_PTR need_to_alloc;
-
-  needs_to_be = (DWORD_PTR) ROUND_UP (get_heap_end (), align);
-  need_to_alloc = needs_to_be - (DWORD_PTR) get_heap_end ();
-
-  if (need_to_alloc)
-    sbrk (need_to_alloc);
-}
+/* Heap management routines for GNU Emacs on the Microsoft Windows
+   API.  Copyright (C) 1994, 2001-2014 Free Software Foundation, Inc.
+
+   This file is part of GNU Emacs.
+
+   GNU Emacs is free software: you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation, either version 3 of the License, or
+   (at your option) any later version.
+
+   GNU Emacs 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 General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>. */
+
+/*
+  Geoff Voelker (voelker@cs.washington.edu)                          7-29-94
+*/
+
+/*
+  Heavily modified by Fabrice Popineau (fabrice.popineau@gmail.com) 28-02-2014
+*/
+
+/*
+  Memory allocation scheme for w32/w64:
+
+  - Buffers are mmap'ed using a very simple emulation of mmap/munmap
+  - During the temacs phase:
+    * we use a private heap declared to be stored into the `dumped_data'
+    * unfortunately, this heap cannot be made growable, so the size of
+      blocks it can allocate is limited to (0x80000 - pagesize)
+    * the blocks that are larger than this are allocated from the end
+      of the `dumped_data' array; there are not so many of them.
+      We use a very simple first-fit scheme to reuse those blocks.
+    * we check that the private heap does not cross the area used
+      by the bigger chunks.
+  - During the emacs phase:
+    * we create a private heap for new memory blocks
+    * we make sure that we never free a block that has been dumped.
+      Freeing a dumped block could work in principle, but may prove
+      unreliable if we distribute binaries of emacs.exe: MS does not
+      guarantee that the heap data structures are the same across all
+      versions of their OS, even though the API is available since XP.  */
+
+#include <config.h>
+#include <stdio.h>
+
+#include <sys/mman.h>
+#include "w32common.h"
+#include "w32heap.h"
+#include "lisp.h"  /* for VALMASK */
+
+/* We chose to leave those declarations here.  They are used only in
+   this file.  The RtlCreateHeap is available since XP.  It is located
+   in ntdll.dll and is available with the DDK.  People often
+   complained that HeapCreate doesn't offer the ability to create a
+   heap at a given place, which we need here, and which RtlCreateHeap
+   provides.  We reproduce here the definitions available with the
+   DDK.  */
+
+typedef PVOID (WINAPI * RtlCreateHeap_Proc) (
+                                             /* _In_ */      ULONG Flags,
+                                             /* _In_opt_ */  PVOID HeapBase,
+                                             /* _In_opt_ */  SIZE_T ReserveSize,
+                                             /* _In_opt_ */  SIZE_T CommitSize,
+                                             /* _In_opt_ */  PVOID Lock,
+                                             /* _In_opt_ */  PVOID Parameters
+                                             );
+
+typedef LONG NTSTATUS;
+
+typedef NTSTATUS
+(NTAPI * PRTL_HEAP_COMMIT_ROUTINE)(
+                                   IN PVOID Base,
+                                   IN OUT PVOID *CommitAddress,
+                                   IN OUT PSIZE_T CommitSize
+                                   );
+
+typedef struct _RTL_HEAP_PARAMETERS {
+  ULONG Length;
+  SIZE_T SegmentReserve;
+  SIZE_T SegmentCommit;
+  SIZE_T DeCommitFreeBlockThreshold;
+  SIZE_T DeCommitTotalFreeThreshold;
+  SIZE_T MaximumAllocationSize;
+  SIZE_T VirtualMemoryThreshold;
+  SIZE_T InitialCommit;
+  SIZE_T InitialReserve;
+  PRTL_HEAP_COMMIT_ROUTINE CommitRoutine;
+  SIZE_T Reserved[ 2 ];
+} RTL_HEAP_PARAMETERS, *PRTL_HEAP_PARAMETERS;
+
+/* We reserve space for dumping emacs lisp byte-code inside a static
+   array.  By storing it in an array, the generic mechanism in
+   unexecw32.c will be able to dump it without the need to add a
+   special segment to the executable.  In order to be able to do this
+   without losing too much space, we need to create a Windows heap at
+   the specific address of the static array.  The RtlCreateHeap
+   available inside the NT kernel since XP will do this.  It allows to
+   create a non-growable heap at a specific address.  So before
+   dumping, we create a non-growable heap at the address of the
+   dumped_data[] array.  After dumping, we reuse memory allocated
+   there without being able to free it (but most of it is not meant to
+   be freed anyway), and we use a new private heap for all new
+   allocations.  */
+
+unsigned char dumped_data[DUMPED_HEAP_SIZE];
+
+/* Info for managing our preload heap, which is essentially a fixed size
+   data area in the executable. */
+/* Info for keeping track of our heap. */
+unsigned char *data_region_base = NULL;
+unsigned char *data_region_end = NULL;
+static DWORD_PTR committed = 0;
+
+/* The maximum block size that can be handled by a non-growable w32
+   heap is limited by the MaxBlockSize value below.
+
+   This point deserves and explanation.
+
+   The W32 heap allocator can be used for a growable
+   heap or a non-growable one.
+
+   A growable heap is not compatible with a fixed base address for the
+   heap.  Only a non-growable one is.  One drawback of non-growable
+   heaps is that they can hold only objects smaller than a certain
+   size (the one defined below).  Most of the largest blocks are GC'ed
+   before dumping.  In any case and to be safe, we implement a simple
+   first-fit allocation algorithm starting at the end of the
+   dumped_data[] array like depicted below:
+
+  ----------------------------------------------
+  |               |              |             |
+  | Private heap  |->          <-|  Big chunks |
+  |               |              |             |
+  ----------------------------------------------
+  ^               ^              ^
+  dumped_data     dumped_data    bc_limit
+                  + committed
+
+*/
+#define HEAP_ENTRY_SHIFT 3
+#define PAGE_SIZE 0x1000
+#define MaxBlockSize (0x80000 - PAGE_SIZE)
+
+#define MAX_BLOCKS 0x40
+
+static struct
+{
+  unsigned char *address;
+  size_t size;
+  DWORD occupied;
+} blocks[MAX_BLOCKS];
+
+static DWORD          blocks_number = 0;
+static unsigned char *bc_limit;
+
+/* Handle for the private heap:
+    - inside the dumped_data[] array before dump,
+    - outside of it after dump.
+*/
+HANDLE heap = NULL;
+
+/* We redirect the standard allocation functions.  */
+malloc_fn the_malloc_fn;
+realloc_fn the_realloc_fn;
+free_fn the_free_fn;
+
+/* It doesn't seem to be useful to allocate from a file mapping.
+   It would be if the memory was shared.
+     http://stackoverflow.com/questions/307060/what-is-the-purpose-of-allocating-pages-in-the-pagefile-with-createfilemapping  */
+
+/* This is the function to commit memory when the heap allocator
+   claims for new memory.  Before dumping, we allocate space
+   from the fixed size dumped_data[] array.
+*/
+NTSTATUS NTAPI
+dumped_data_commit (PVOID Base, PVOID *CommitAddress, PSIZE_T CommitSize)
+{
+  /* This is used before dumping.
+
+     The private heap is stored at dumped_data[] address.
+     We commit contiguous areas of the dumped_data array
+     as requests arrive.  */
+  *CommitAddress = data_region_base + committed;
+  committed += *CommitSize;
+  if (((unsigned char *)(*CommitAddress)) + *CommitSize >= bc_limit)
+    {
+      /* Check that the private heap area does not overlap the big
+        chunks area.  */
+      fprintf(stderr,
+             "dumped_data_commit: memory exhausted.\nEnlarge dumped_data[]!\n");
+      exit (-1);
+    }
+  return 0;
+}
+
+/* Heap creation.  */
+
+/* Under MinGW32, we want to turn on Low Fragmentation Heap for XP.
+   MinGW32 lacks those definitions.  */
+#ifndef _W64
+typedef enum _HEAP_INFORMATION_CLASS {
+  HeapCompatibilityInformation
+} HEAP_INFORMATION_CLASS;
+
+typedef WINBASEAPI BOOL (WINAPI * HeapSetInformation_Proc)(HANDLE,HEAP_INFORMATION_CLASS,PVOID,SIZE_T);
+#endif
+
+void
+init_heap (void)
+{
+  if (using_dynamic_heap)
+    {
+      unsigned long enable_lfh = 2;
+
+      /* After dumping, use a new private heap.  We explicitly enable
+         the low fragmentation heap here, for the sake of pre Vista
+         versions.  Note: this will harnlessly fail on Vista and
+         later, whyere the low fragmentation heap is enabled by
+         default.  It will also fail on pre-Vista versions when Emacs
+         is run under a debugger; set _NO_DEBUG_HEAP=1 in the
+         environment before starting GDB to get low fragmentation heap
+         on XP and older systems, for the price of losing "certain
+         heap debug options"; for the details see
+         http://msdn.microsoft.com/en-us/library/windows/desktop/aa366705%28v=vs.85%29.aspx.  */
+      data_region_end = data_region_base;
+
+      /* Create the private heap.  */
+      heap = HeapCreate(0, 0, 0);
+
+#ifndef _W64
+      /* Set the low-fragmentation heap for OS before XP and Windows
+        Server 2003.  */
+      HMODULE hm_kernel32dll = LoadLibrary("kernel32.dll");
+      HeapSetInformation_Proc s_pfn_Heap_Set_Information = (HeapSetInformation_Proc) GetProcAddress(hm_kernel32dll, "HeapSetInformation");
+      if (s_pfn_Heap_Set_Information != NULL)
+        if (s_pfn_Heap_Set_Information ((PVOID) heap,
+                                        HeapCompatibilityInformation,
+                                        &enable_lfh, sizeof(enable_lfh)) == 0)
+          DebPrint (("Enabling Low Fragmentation Heap failed\n"));
+#endif
+
+      the_malloc_fn = malloc_after_dump;
+      the_realloc_fn = realloc_after_dump;
+      the_free_fn = free_after_dump;
+    }
+  else
+    {
+      /* Find the RtlCreateHeap function.  Headers for this function
+         are provided with the w32 ddk, but the function is available
+         in ntdll.dll since XP.  */
+      HMODULE hm_ntdll = LoadLibrary ("ntdll.dll");
+      RtlCreateHeap_Proc s_pfn_Rtl_Create_Heap
+       = (RtlCreateHeap_Proc) GetProcAddress (hm_ntdll, "RtlCreateHeap");
+      /* Specific parameters for the private heap.  */
+      RTL_HEAP_PARAMETERS params;
+      ZeroMemory(&params, sizeof(params));
+      params.Length = sizeof(RTL_HEAP_PARAMETERS);
+
+      data_region_base = (unsigned char *)ROUND_UP (dumped_data, 0x1000);
+      data_region_end = bc_limit = dumped_data + DUMPED_HEAP_SIZE;
+
+      params.InitialCommit = committed = 0x1000;
+      params.InitialReserve = sizeof(dumped_data);
+      /* Use our own routine to commit memory from the dumped_data
+         array.  */
+      params.CommitRoutine = &dumped_data_commit;
+
+      /* Create the private heap.  */
+      heap = s_pfn_Rtl_Create_Heap (0, data_region_base, 0, 0, NULL, &params);
+      the_malloc_fn = malloc_before_dump;
+      the_realloc_fn = realloc_before_dump;
+      the_free_fn = free_before_dump;
+    }
+
+  /* Update system version information to match current system.  */
+  cache_system_info ();
+}
+
+#undef malloc
+#undef realloc
+#undef calloc
+#undef free
+
+/* FREEABLE_P checks if the block can be safely freed.  */
+#define FREEABLE_P(addr)                                        \
+    ((unsigned char *)(addr) < dumped_data                      \
+     || (unsigned char *)(addr) >= dumped_data + DUMPED_HEAP_SIZE)
+
+void *
+malloc_after_dump (size_t size)
+{
+  /* Use the new private heap.  */
+  void *p = HeapAlloc (heap, 0, size);
+
+  /* After dump, keep track of the last allocated byte for sbrk(0).  */
+  data_region_end = p + size - 1;
+  return p;
+}
+
+void *
+malloc_before_dump (size_t size)
+{
+  void *p;
+
+  /* Before dumping.  The private heap can handle only requests for
+     less than MaxBlockSize.  */
+  if (size < MaxBlockSize)
+    {
+      /* Use the private heap if possible.  */
+      p = HeapAlloc (heap, 0, size);
+    }
+  else
+    {
+      /* Find the first big chunk that can hold the requested size.  */
+      int i = 0;
+
+      for (i = 0; i < blocks_number; i++)
+       {
+         if (blocks[i].occupied == 0 && blocks[i].size >= size)
+           break;
+       }
+      if (i < blocks_number)
+       {
+         /* If found, use it.  */
+         p = blocks[i].address;
+         blocks[i].occupied = TRUE;
+       }
+      else
+       {
+         /* Allocate a new big chunk from the end of the dumped_data
+            array.  */
+         if (blocks_number >= MAX_BLOCKS)
+           {
+             fprintf(stderr,
+                     "malloc_before_dump: no more big chunks available.\nEnlarge MAX_BLOCKS!\n");
+             exit (-1);
+           }
+         bc_limit -= size;
+         bc_limit = (unsigned char *)ROUND_DOWN (bc_limit, 0x10);
+         p = bc_limit;
+         blocks[blocks_number].address = p;
+         blocks[blocks_number].size = size;
+         blocks[blocks_number].occupied = TRUE;
+         blocks_number++;
+         if (bc_limit < dumped_data + committed)
+           {
+             /* Check that areas do not overlap.  */
+             fprintf(stderr,
+                     "malloc_before_dump: memory exhausted.\nEnlarge dumped_data[]!\n");
+             exit (-1);
+           }
+       }
+    }
+  return p;
+}
+
+/* Re-allocate the previously allocated block in ptr, making the new
+   block SIZE bytes long.  */
+void *
+realloc_after_dump (void *ptr, size_t size)
+{
+  void *p;
+
+  /* After dumping.  */
+  if (FREEABLE_P (ptr))
+    {
+      /* Reallocate the block since it lies in the new heap.  */
+      p = HeapReAlloc (heap, 0, ptr, size);
+    }
+  else
+    {
+      /* If the block lies in the dumped data, do not free it.  Only
+         allocate a new one.  */
+      p = HeapAlloc (heap, 0, size);
+      CopyMemory (p, ptr, size);
+    }
+  /* After dump, keep track of the last allocated byte for sbrk(0).  */
+  data_region_end = p + size - 1;
+  return p;
+}
+
+void *
+realloc_before_dump (void *ptr, size_t size)
+{
+  void *p;
+
+  /* Before dumping.  */
+  if (dumped_data < (unsigned char *)ptr
+      && (unsigned char *)ptr < bc_limit && size <= MaxBlockSize)
+    p = HeapReAlloc (heap, 0, ptr, size);
+  else
+    {
+      /* In this case, either the new block is too large for the heap,
+         or the old block was already too large.  In both cases,
+         malloc_before_dump() and free_before_dump() will take care of
+         reallocation.  */
+      p = malloc_before_dump (size);
+      CopyMemory (p, ptr, size);
+      free_before_dump (ptr);
+    }
+  return p;
+}
+
+/* Free a block allocated by `malloc', `realloc' or `calloc'.  */
+void
+free_after_dump (void *ptr)
+{
+  /* After dumping.  */
+  if (FREEABLE_P (ptr))
+    {
+      /* Free the block if it is in the new private heap.  */
+      HeapFree (heap, 0, ptr);
+    }
+}
+
+void
+free_before_dump (void *ptr)
+{
+  /* Before dumping.  */
+  if (dumped_data < (unsigned char *)ptr
+      && (unsigned char *)ptr < bc_limit)
+    {
+      /* Free the block if it is allocated in the private heap.  */
+      HeapFree (heap, 0, ptr);
+    }
+  else
+    {
+      /* Look for the big chunk.  */
+      int i;
+
+      for(i = 0; i < blocks_number; i++)
+       {
+         if (blocks[i].address == ptr)
+           {
+             /* Reset block occupation if found.  */
+             blocks[i].occupied = 0;
+             break;
+           }
+         /* What if the block is not found?  We should trigger an
+            error here.  */
+         eassert (i < blocks_number);
+       }
+    }
+}
+
+/* Emulate getpagesize. */
+int
+getpagesize (void)
+{
+  return sysinfo_cache.dwPageSize;
+}
+
+void *
+sbrk (ptrdiff_t increment)
+{
+  /* The data_region_end address is the one of the last byte
+     allocated.  The sbrk() function is not emulated at all, except
+     for a 0 value of its parameter.  This is needed by the emacs lisp
+     function `memory-limit'.   */
+  return data_region_end;
+}
+
+#define MAX_BUFFER_SIZE (512 * 1024 * 1024)
+
+/* MMAP allocation for buffers.  */
+void *
+mmap_alloc (void **var, size_t nbytes)
+{
+  void *p = NULL;
+
+  /* We implement amortized allocation.  We start by reserving twice
+     the size requested and commit only the size requested.  Then
+     realloc could proceed and use the reserved pages, reallocating
+     only if needed.  Buffer shrink would happen only so that we stay
+     in the 2x range.  This is a big win when visiting compressed
+     files, where the final size of the buffer is not known in
+     advance, and the buffer is enlarged several times as the data is
+     decompressed on the fly.  */
+  if (nbytes < MAX_BUFFER_SIZE)
+    p = VirtualAlloc (NULL, (nbytes * 2), MEM_RESERVE, PAGE_READWRITE);
+
+  /* If it fails, or if the request is above 512MB, try with the
+     requested size.  */
+  if (p == NULL)
+    p = VirtualAlloc (NULL, nbytes, MEM_RESERVE, PAGE_READWRITE);
+
+  if (p != NULL)
+    {
+      /* Now, commit pages for NBYTES.  */
+      *var = VirtualAlloc (p, nbytes, MEM_COMMIT, PAGE_READWRITE);
+    }
+
+  if (!p && GetLastError () != ERROR_NOT_ENOUGH_MEMORY)
+    DebPrint (("mmap_alloc: error %ld\n", GetLastError()));
+
+  return *var = p;
+}
+
+void
+mmap_free (void **var)
+{
+  if (*var)
+    {
+      if (VirtualFree (*var, 0, MEM_RELEASE) == 0)
+        DebPrint (("mmap_free: error %ld\n", GetLastError()));
+      *var = NULL;
+    }
+}
+
+void *
+mmap_realloc (void **var, size_t nbytes)
+{
+  MEMORY_BASIC_INFORMATION memInfo, m2;
+
+  if (*var == NULL)
+    return mmap_alloc (var, nbytes);
+
+  /* This case happens in init_buffer().  */
+  if (nbytes == 0)
+    {
+      mmap_free (var);
+      return mmap_alloc (var, nbytes);
+    }
+
+  if (VirtualQuery (*var, &memInfo, sizeof (memInfo)) == 0)
+    DebPrint (("mmap_realloc: VirtualQuery error = %ld\n", GetLastError()));
+
+  /* We need to enlarge the block.  */
+  if (memInfo.RegionSize < nbytes)
+    {
+      if (VirtualQuery (*var + memInfo.RegionSize, &m2, sizeof(m2)) == 0)
+        DebPrint (("mmap_realloc: VirtualQuery error = %ld\n", GetLastError()));
+      /* If there is enough room in the current reserved area, then
+        commit more pages as needed.  */
+      if (m2.State == MEM_RESERVE
+         && nbytes <= memInfo.RegionSize + m2.RegionSize)
+       {
+         void *p;
+
+         p = VirtualAlloc (*var + memInfo.RegionSize,
+                           nbytes - memInfo.RegionSize,
+                           MEM_COMMIT, PAGE_READWRITE);
+         if (!p /* && GetLastError() != ERROR_NOT_ENOUGH_MEMORY */)
+           DebPrint (("realloc enlarge: VirtualAlloc error %ld\n",
+                      GetLastError()));
+         return *var;
+       }
+      else
+       {
+         /* Else we must actually enlarge the block by allocating a
+            new one and copying previous contents from the old to the
+            new one.  */
+         void *old_ptr = *var;
+
+         if (mmap_alloc (var, nbytes))
+           {
+             CopyMemory (*var, old_ptr, memInfo.RegionSize);
+             mmap_free (&old_ptr);
+             return *var;
+           }
+         else
+           {
+             /* We failed to enlarge the buffer.  */
+             *var = old_ptr;
+             return NULL;
+           }
+       }
+    }
+
+  /* If we are shrinking by more than one page...  */
+  if (memInfo.RegionSize  > nbytes + getpagesize())
+    {
+      /* If we are shrinking a lot...  */
+      if ((memInfo.RegionSize / 2) > nbytes)
+        {
+          /* Let's give some memory back to the system and release
+            some pages.  */
+          void *old_ptr = *var;
+
+         if (mmap_alloc (var, nbytes))
+            {
+              CopyMemory (*var, old_ptr, nbytes);
+              mmap_free (&old_ptr);
+              return *var;
+            }
+          else
+           {
+             /* In case we fail to shrink, try to go on with the old block.
+                But that means there is a lot of memory pressure.
+                We could also decommit pages.  */
+             *var = old_ptr;
+             return *var;
+           }
+        }
+
+      /* We still can decommit pages.  */
+      if (VirtualFree (*var + nbytes + get_page_size(),
+                      memInfo.RegionSize - nbytes - get_page_size(),
+                      MEM_DECOMMIT) == 0)
+        DebPrint (("mmap_realloc: VirtualFree error %ld\n", GetLastError()));
+      return *var;
+    }
+
+  /* Not enlarging, not shrinking by more than one page.  */
+  return *var;
+}
index d5791a3..84a26f9 100644 (file)
@@ -27,15 +27,20 @@ along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.
 /*
  * Heap related stuff.
  */
-#define get_reserved_heap_size()       reserved_heap_size
-#define get_committed_heap_size()      (get_data_end () - get_data_start ())
-#define get_heap_start()               get_data_start ()
-#define get_heap_end()                 get_data_end ()
+
+#define DUMPED_HEAP_SIZE (HEAPSIZE*1024*1024)
+
+extern unsigned char dumped_data[];
 
 extern unsigned char *get_data_start (void);
 extern unsigned char *get_data_end (void);
 extern size_t         reserved_heap_size;
-extern BOOL          using_dynamic_heap;
+extern BOOL           using_dynamic_heap;
+
+extern void *mmap_realloc (void **, size_t);
+extern void  mmap_free (void **);
+extern void *mmap_alloc (void **, size_t);
+
 
 /* Emulation of Unix sbrk().  */
 extern void *sbrk (ptrdiff_t size);
@@ -43,11 +48,8 @@ extern void *sbrk (ptrdiff_t size);
 /* Initialize heap structures for sbrk on startup.  */
 extern void init_heap (void);
 
-/* Round the heap to this size.  */
-extern void round_heap (size_t size);
-
 /* ----------------------------------------------------------------- */
-/* Useful routines for manipulating memory-mapped files. */
+/* Useful routines for manipulating memory-mapped files.  */
 
 typedef struct file_data {
     char          *name;
@@ -61,11 +63,11 @@ int open_input_file (file_data *p_file, char *name);
 int open_output_file (file_data *p_file, char *name, unsigned long size);
 void close_file_data (file_data *p_file);
 
-/* Return pointer to section header for named section. */
+/* Return pointer to section header for named section.  */
 IMAGE_SECTION_HEADER * find_section (char * name, IMAGE_NT_HEADERS * nt_header);
 
 /* Return pointer to section header for section containing the given
-   relative virtual address. */
+   relative virtual address.  */
 IMAGE_SECTION_HEADER * rva_to_section (DWORD_PTR rva, IMAGE_NT_HEADERS * nt_header);
 
 #endif /* NTHEAP_H_ */