aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorFabrice Popineau2014-05-27 20:31:17 +0300
committerEli Zaretskii2014-05-27 20:31:17 +0300
commit587fd086a045f715932f886ecf31015932464ce6 (patch)
treed8c647af107ef94318fd920a05da09af654ef1c9
parent0da7d35c6754b44d1ef4383e4a8ba9b98afc3a4c (diff)
downloademacs-587fd086a045f715932f886ecf31015932464ce6.tar.gz
emacs-587fd086a045f715932f886ecf31015932464ce6.zip
Use mmap(2) emulation for buffer text on MS-Windows.
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.
-rw-r--r--ChangeLog7
-rw-r--r--configure.ac22
-rw-r--r--etc/ChangeLog4
-rw-r--r--etc/NEWS5
-rw-r--r--nt/ChangeLog9
-rw-r--r--nt/INSTALL21
-rw-r--r--nt/inc/ms-w32.h33
-rw-r--r--nt/inc/sys/mman.h31
-rw-r--r--src/ChangeLog32
-rw-r--r--src/Makefile.in9
-rw-r--r--src/buffer.c69
-rw-r--r--src/emacs.c7
-rw-r--r--src/image.c6
-rw-r--r--src/lisp.h2
-rw-r--r--src/unexw32.c48
-rw-r--r--src/w32heap.c733
-rw-r--r--src/w32heap.h24
17 files changed, 720 insertions, 342 deletions
diff --git a/ChangeLog b/ChangeLog
index 28c877a18bb..09f06181136 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,10 @@
12014-05-27 Fabrice Popineau <fabrice.popineau@gmail.com>
2
3 * configure.ac (C_HEAP_SWITCH) define for different values of
4 dumped heap size depending on 32/64bits arch on Windows.
5 Don't check for pthreads.h on MinGW32/64, it gets in the way.
6 Use mmap(2) for buffers and system malloc for MinGW32/64.
7
12014-05-27 Paul Eggert <eggert@cs.ucla.edu> 82014-05-27 Paul Eggert <eggert@cs.ucla.edu>
2 9
3 Merge from gnulib, incorporating: 10 Merge from gnulib, incorporating:
diff --git a/configure.ac b/configure.ac
index d727c0253f8..84f989f7f97 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1973,7 +1973,7 @@ doug_lea_malloc=$emacs_cv_var_doug_lea_malloc
1973system_malloc=$emacs_cv_sanitize_address 1973system_malloc=$emacs_cv_sanitize_address
1974case "$opsys" in 1974case "$opsys" in
1975 ## darwin ld insists on the use of malloc routines in the System framework. 1975 ## darwin ld insists on the use of malloc routines in the System framework.
1976 darwin|sol2-10) system_malloc=yes ;; 1976 darwin|mingw32|sol2-10) system_malloc=yes ;;
1977esac 1977esac
1978 1978
1979GMALLOC_OBJ= 1979GMALLOC_OBJ=
@@ -2020,7 +2020,7 @@ if test "$doug_lea_malloc" = "yes" ; then
2020 ## #ifdef DOUG_LEA_MALLOC; #undef REL_ALLOC; #endif 2020 ## #ifdef DOUG_LEA_MALLOC; #undef REL_ALLOC; #endif
2021 ## Does the AC_FUNC_MMAP test below make this check unnecessary? 2021 ## Does the AC_FUNC_MMAP test below make this check unnecessary?
2022 case "$opsys" in 2022 case "$opsys" in
2023 gnu*) REL_ALLOC=no ;; 2023 mingw32|gnu*) REL_ALLOC=no ;;
2024 esac 2024 esac
2025fi 2025fi
2026 2026
@@ -2030,7 +2030,7 @@ fi
2030 2030
2031use_mmap_for_buffers=no 2031use_mmap_for_buffers=no
2032case "$opsys" in 2032case "$opsys" in
2033 cygwin|freebsd|irix6-5) use_mmap_for_buffers=yes ;; 2033 cygwin|mingw32|freebsd|irix6-5) use_mmap_for_buffers=yes ;;
2034esac 2034esac
2035 2035
2036AC_FUNC_MMAP 2036AC_FUNC_MMAP
@@ -2046,6 +2046,7 @@ AC_CHECK_LIB(Xbsd, main, LD_SWITCH_X_SITE="$LD_SWITCH_X_SITE -lXbsd")
2046 2046
2047dnl Check for the POSIX thread library. 2047dnl Check for the POSIX thread library.
2048LIB_PTHREAD= 2048LIB_PTHREAD=
2049if test "$opsys" != "mingw32"; then
2049AC_CHECK_HEADERS_ONCE(pthread.h) 2050AC_CHECK_HEADERS_ONCE(pthread.h)
2050if test "$ac_cv_header_pthread_h"; then 2051if test "$ac_cv_header_pthread_h"; then
2051 dnl gmalloc.c uses pthread_atfork, which is not available on older-style 2052 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
2066 LIBS=$OLD_LIBS 2067 LIBS=$OLD_LIBS
2067fi 2068fi
2068AC_SUBST([LIB_PTHREAD]) 2069AC_SUBST([LIB_PTHREAD])
2070fi
2069 2071
2070dnl Check for need for bigtoc support on IBM AIX 2072dnl Check for need for bigtoc support on IBM AIX
2071 2073
@@ -4817,11 +4819,9 @@ case "$opsys" in
4817 gnu*) LD_SWITCH_SYSTEM_TEMACS="\$(LD_SWITCH_X_SITE_RPATH)" ;; 4819 gnu*) LD_SWITCH_SYSTEM_TEMACS="\$(LD_SWITCH_X_SITE_RPATH)" ;;
4818 4820
4819 mingw32) 4821 mingw32)
4820 ## MinGW64 does not prepend an underscore to symbols, so we must 4822 ## Is it any better under MinGW64 to relocate emacs into higher addresses?
4821 ## pass a different -entry switch to linker. FIXME: It is better
4822 ## to make the entry points the same by changing unexw32.c.
4823 case "$canonical" in 4823 case "$canonical" in
4824 x86_64-*-*) LD_SWITCH_SYSTEM_TEMACS="-Wl,-stack,0x00800000 -Wl,-heap,0x00100000 -Wl,-image-base,0x01000000 -Wl,-entry,__start -Wl,-Map,./temacs.map" ;; 4824 x86_64-*-*) LD_SWITCH_SYSTEM_TEMACS="-Wl,-stack,0x00800000 -Wl,-heap,0x00100000 -Wl,-image-base,0x400000000 -Wl,-entry,__start -Wl,-Map,./temacs.map" ;;
4825 *) LD_SWITCH_SYSTEM_TEMACS="-Wl,-stack,0x00800000 -Wl,-heap,0x00100000 -Wl,-image-base,0x01000000 -Wl,-entry,__start -Wl,-Map,./temacs.map" ;; 4825 *) LD_SWITCH_SYSTEM_TEMACS="-Wl,-stack,0x00800000 -Wl,-heap,0x00100000 -Wl,-image-base,0x01000000 -Wl,-entry,__start -Wl,-Map,./temacs.map" ;;
4826 esac 4826 esac
4827 ;; 4827 ;;
@@ -4845,20 +4845,20 @@ AC_SUBST(LD_SWITCH_SYSTEM_TEMACS)
4845## MinGW-specific post-link processing of temacs. 4845## MinGW-specific post-link processing of temacs.
4846TEMACS_POST_LINK=":" 4846TEMACS_POST_LINK=":"
4847ADDSECTION= 4847ADDSECTION=
4848EMACS_HEAPSIZE= 4848C_HEAP_SWITCH=
4849if test "${opsys}" = "mingw32"; then 4849if test "${opsys}" = "mingw32"; then
4850 TEMACS_POST_LINK="\$(MINGW_TEMACS_POST_LINK)" 4850 TEMACS_POST_LINK="\$(MINGW_TEMACS_POST_LINK)"
4851 ADDSECTION="../nt/addsection\$(EXEEXT)" 4851 ADDSECTION="../nt/addsection\$(EXEEXT)"
4852 ## Preload heap size of temacs.exe in MB. 4852 ## Preload heap size of temacs.exe in MB.
4853 case "$canonical" in 4853 case "$canonical" in
4854 x86_64-*-*) EMACS_HEAPSIZE=42 ;; 4854 x86_64-*-*) C_HEAP_SWITCH="-DHEAPSIZE=18" ;;
4855 *) EMACS_HEAPSIZE=27 ;; 4855 *) C_HEAP_SWITCH="-DHEAPSIZE=10" ;;
4856 esac 4856 esac
4857fi 4857fi
4858 4858
4859AC_SUBST(ADDSECTION) 4859AC_SUBST(ADDSECTION)
4860AC_SUBST(TEMACS_POST_LINK) 4860AC_SUBST(TEMACS_POST_LINK)
4861AC_SUBST(EMACS_HEAPSIZE) 4861AC_SUBST(C_HEAP_SWITCH)
4862 4862
4863## Common for all window systems 4863## Common for all window systems
4864if test "$window_system" != "none"; then 4864if test "$window_system" != "none"; then
diff --git a/etc/ChangeLog b/etc/ChangeLog
index 49be20a5f79..27ee804400e 100644
--- a/etc/ChangeLog
+++ b/etc/ChangeLog
@@ -1,3 +1,7 @@
12014-05-27 Fabrice Popineau <fabrice.popineau@gmail.com>
2
3 * NEWS: Mention build changes on MS-Windows.
4
12014-05-26 Paul Eggert <eggert@cs.ucla.edu> 52014-05-26 Paul Eggert <eggert@cs.ucla.edu>
2 6
3 Specify coding if Latin-1 Emacs would misinterpret (Bug#17575). 7 Specify coding if Latin-1 Emacs would misinterpret (Bug#17575).
diff --git a/etc/NEWS b/etc/NEWS
index 3d76642fe52..20112451a37 100644
--- a/etc/NEWS
+++ b/etc/NEWS
@@ -40,6 +40,11 @@ or by sticking with Emacs 24.4.
40** The configure option `--with-pkg-config-prog' has been removed. 40** The configure option `--with-pkg-config-prog' has been removed.
41Use './configure PKG_CONFIG=/full/name/of/pkg-config' if you need to. 41Use './configure PKG_CONFIG=/full/name/of/pkg-config' if you need to.
42 42
43---
44** Building Emacs for MS-Windows requires at least Windows XP
45or Windows Server 2003. The built binaries still run on all versions
46of Windows starting with Windows 9X.
47
43 48
44* Startup Changes in Emacs 24.5 49* Startup Changes in Emacs 24.5
45 50
diff --git a/nt/ChangeLog b/nt/ChangeLog
index a3cb5e62dac..961de329ad5 100644
--- a/nt/ChangeLog
+++ b/nt/ChangeLog
@@ -1,3 +1,12 @@
12014-05-27 Fabrice Popineau <fabrice.popineau@gmail.com>
2
3 * inc/ms-w32.h: Switch to the system heap allocation scheme
4 instead of GNU malloc and ralloc.
5
6 * inc/sys/mman.h: New file.
7
8 * INSTALL: Update for the new build requirements.
9
12014-05-17 Paul Eggert <eggert@cs.ucla.edu> 102014-05-17 Paul Eggert <eggert@cs.ucla.edu>
2 11
3 Assume C99 or later (Bug#17487). 12 Assume C99 or later (Bug#17487).
diff --git a/nt/INSTALL b/nt/INSTALL
index 949a4e452cf..4ecf4da3181 100644
--- a/nt/INSTALL
+++ b/nt/INSTALL
@@ -5,9 +5,9 @@
5 See the end of the file for license conditions. 5 See the end of the file for license conditions.
6 6
7The MSYS/MinGW build described here is supported on versions of 7The MSYS/MinGW build described here is supported on versions of
8Windows starting with Windows 2000 and newer. Windows 9X are not 8Windows starting with Windows XP and newer. Building on Windows 2000
9supported (but the Emacs binary produced by this build will run on 9and Windows 9X is not supported (but the Emacs binary produced by this
10Windows 9X as well). 10build will run on Windows 9X and newer systems).
11 11
12 Do not use this recipe with Cygwin. For building on Cygwin, use the 12 Do not use this recipe with Cygwin. For building on Cygwin, use the
13 normal installation instructions, ../INSTALL. 13 normal installation instructions, ../INSTALL.
@@ -389,9 +389,10 @@ Windows 9X as well).
389 389
390 Where should the build process find the source code? /path/to/emacs/sources 390 Where should the build process find the source code? /path/to/emacs/sources
391 What compiler should emacs be built with? gcc -std=gnu99 -O0 -g3 391 What compiler should emacs be built with? gcc -std=gnu99 -O0 -g3
392 Should Emacs use the GNU version of malloc? yes 392 Should Emacs use the GNU version of malloc? no
393 Should Emacs use a relocating allocator for buffers? yes 393 (The GNU allocators don't work with this system configuration.)
394 Should Emacs use mmap(2) for buffer allocation? no 394 Should Emacs use a relocating allocator for buffers? no
395 Should Emacs use mmap(2) for buffer allocation? yes
395 What window system should Emacs use? w32 396 What window system should Emacs use? w32
396 What toolkit should Emacs use? none 397 What toolkit should Emacs use? none
397 Where do we find X Windows header files? NONE 398 Where do we find X Windows header files? NONE
@@ -401,13 +402,16 @@ Windows 9X as well).
401 Does Emacs use -ljpeg? yes 402 Does Emacs use -ljpeg? yes
402 Does Emacs use -ltiff? yes 403 Does Emacs use -ltiff? yes
403 Does Emacs use a gif library? yes 404 Does Emacs use a gif library? yes
404 Does Emacs use -lpng? yes 405 Does Emacs use a png library? yes
405 Does Emacs use -lrsvg-2? no 406 Does Emacs use -lrsvg-2? yes
406 Does Emacs use imagemagick? no 407 Does Emacs use imagemagick? no
408 Does Emacs support sound? no
407 Does Emacs use -lgpm? no 409 Does Emacs use -lgpm? no
408 Does Emacs use -ldbus? no 410 Does Emacs use -ldbus? no
409 Does Emacs use -lgconf? no 411 Does Emacs use -lgconf? no
410 Does Emacs use GSettings? no 412 Does Emacs use GSettings? no
413 Does Emacs use a file notification library? yes (w32)
414 Does Emacs use access control lists? yes
411 Does Emacs use -lselinux? no 415 Does Emacs use -lselinux? no
412 Does Emacs use -lgnutls? yes 416 Does Emacs use -lgnutls? yes
413 Does Emacs use -lxml2? yes 417 Does Emacs use -lxml2? yes
@@ -415,6 +419,7 @@ Windows 9X as well).
415 Does Emacs use -lm17n-flt? no 419 Does Emacs use -lm17n-flt? no
416 Does Emacs use -lotf? no 420 Does Emacs use -lotf? no
417 Does Emacs use -lxft? no 421 Does Emacs use -lxft? no
422 Does Emacs directly use zlib? yes
418 Does Emacs use toolkit scroll bars? yes 423 Does Emacs use toolkit scroll bars? yes
419 424
420 You are almost there, hang on. 425 You are almost there, hang on.
diff --git a/nt/inc/ms-w32.h b/nt/inc/ms-w32.h
index 8f7c36ab1ee..1cf78bac83a 100644
--- a/nt/inc/ms-w32.h
+++ b/nt/inc/ms-w32.h
@@ -140,6 +140,7 @@ extern char *getenv ();
140 in its system headers, and is not really compatible with values 140 in its system headers, and is not really compatible with values
141 lower than 0x0500, so leave it alone. */ 141 lower than 0x0500, so leave it alone. */
142#ifndef _W64 142#ifndef _W64
143# undef _WIN32_WINNT
143# define _WIN32_WINNT 0x0400 144# define _WIN32_WINNT 0x0400
144#endif 145#endif
145 146
@@ -427,20 +428,36 @@ extern char *get_emacs_configuration_options (void);
427#define _WINSOCK_H 428#define _WINSOCK_H
428 429
429/* Defines size_t and alloca (). */ 430/* Defines size_t and alloca (). */
430#ifdef emacs 431#include <stdlib.h>
431#define malloc e_malloc 432#include <sys/stat.h>
432#define free e_free
433#define realloc e_realloc
434#define calloc e_calloc
435#endif
436#ifdef _MSC_VER 433#ifdef _MSC_VER
437#define alloca _alloca 434#define alloca _alloca
438#else 435#else
439#include <malloc.h> 436#include <malloc.h>
440#endif 437#endif
441 438
442#include <stdlib.h> 439#ifdef emacs
443#include <sys/stat.h> 440
441typedef void * (* malloc_fn)(size_t);
442typedef void * (* realloc_fn)(void *, size_t);
443typedef void (* free_fn)(void *);
444
445extern void *malloc_before_dump(size_t);
446extern void *realloc_before_dump(void *, size_t);
447extern void free_before_dump(void *);
448extern void *malloc_after_dump(size_t);
449extern void *realloc_after_dump(void *, size_t);
450extern void free_after_dump(void *);
451
452extern malloc_fn the_malloc_fn;
453extern realloc_fn the_realloc_fn;
454extern free_fn the_free_fn;
455
456#define malloc(size) (*the_malloc_fn)(size)
457#define free(ptr) (*the_free_fn)(ptr)
458#define realloc(ptr, size) (*the_realloc_fn)(ptr, size)
459
460#endif
444 461
445/* Define for those source files that do not include enough NT system files. */ 462/* Define for those source files that do not include enough NT system files. */
446#ifndef NULL 463#ifndef NULL
diff --git a/nt/inc/sys/mman.h b/nt/inc/sys/mman.h
new file mode 100644
index 00000000000..6990edcb59b
--- /dev/null
+++ b/nt/inc/sys/mman.h
@@ -0,0 +1,31 @@
1/*
2 * sys/mman.h
3 * mman-win32
4 */
5
6#ifndef _SYS_MMAN_H_
7#define _SYS_MMAN_H_
8
9#include <sys/types.h>
10
11#ifdef __cplusplus
12extern "C" {
13#endif
14
15/* We need MAP_ANON in src/buffer.c */
16
17#define MAP_FILE 0
18#define MAP_SHARED 1
19#define MAP_PRIVATE 2
20#define MAP_TYPE 0xf
21#define MAP_FIXED 0x10
22#define MAP_ANONYMOUS 0x20
23#define MAP_ANON MAP_ANONYMOUS
24
25#define MAP_FAILED ((void *)-1)
26
27#ifdef __cplusplus
28};
29#endif
30
31#endif /* _SYS_MMAN_H_ */
diff --git a/src/ChangeLog b/src/ChangeLog
index 4378cfce5d3..959f29a2675 100644
--- a/src/ChangeLog
+++ b/src/ChangeLog
@@ -1,3 +1,35 @@
12014-05-27 Fabrice Popineau <fabrice.popineau@gmail.com>
2
3 * Makefile.in (C_HEAP_SWITCH): Get the predefined heap size from
4 configure.
5 (ADDSECTION, MINGW_TEMACS_POST_LINK): Remove, no longer used.
6
7 * lisp.h (NONPOINTER_BITS): Modify the condition to define to zero
8 for MinGW, since it no longer uses gmalloc.
9
10 * buffer.c: Do not define mmap allocations functions for Windows.
11 Remove mmap_find which is unused. Remove mmap_set_vars which does
12 nothing useful.
13 [WINDOWSNT]: Include w32heap.h.
14 (init_buffer): Always allocate new memory for buffers.
15
16 * emacs.c: Remove mmap_set_vars calls.
17
18 * image.c (free_image): Undef free for Windows because it is
19 redirected to our private version.
20
21 * unexw32.c (COPY_PROC_CHUNK): Use %p format for 64bits
22 compatibility.
23 (copy_executable_and_dump_data): Remove dumping the heap section.
24 (unexec): Restore using_dynamic_heap after dumping.
25
26 * w32heap.c (dumped_data_commit, malloc_after_dump)
27 (malloc_before_dump, realloc_after_dump, realloc_before_dump)
28 (free_after_dump, free_before_dump, mmap_alloc, mmap_realloc)
29 (mmap_free): New functions.
30
31 * w32heap.h: Declare dumped_data and mmap_* function prototypes.
32
12014-05-27 Paul Eggert <eggert@cs.ucla.edu> 332014-05-27 Paul Eggert <eggert@cs.ucla.edu>
2 34
3 * image.c (imagemagick_load_image): Use MagickRealType for local 35 * image.c (imagemagick_load_image): Use MagickRealType for local
diff --git a/src/Makefile.in b/src/Makefile.in
index b4e9eae330b..0f4130b4dac 100644
--- a/src/Makefile.in
+++ b/src/Makefile.in
@@ -86,6 +86,9 @@ PNG_CFLAGS=@PNG_CFLAGS@
86## something similar. This is normally set by configure. 86## something similar. This is normally set by configure.
87C_SWITCH_X_SITE=@C_SWITCH_X_SITE@ 87C_SWITCH_X_SITE=@C_SWITCH_X_SITE@
88 88
89## Set Emacs dumped heap size for Windows NT
90C_HEAP_SWITCH=@C_HEAP_SWITCH@
91
89## Define LD_SWITCH_X_SITE to contain any special flags your loader 92## Define LD_SWITCH_X_SITE to contain any special flags your loader
90## may need to deal with X Windows. For instance, if your X libraries 93## may need to deal with X Windows. For instance, if your X libraries
91## aren't in a place that your loader can find on its own, you might 94## aren't in a place that your loader can find on its own, you might
@@ -300,11 +303,7 @@ RUN_TEMACS = ./temacs
300 303
301## Invoke ../nt/addsection for MinGW, ":" elsewhere. 304## Invoke ../nt/addsection for MinGW, ":" elsewhere.
302TEMACS_POST_LINK = @TEMACS_POST_LINK@ 305TEMACS_POST_LINK = @TEMACS_POST_LINK@
303ADDSECTION = @ADDSECTION@
304EMACS_HEAPSIZE = @EMACS_HEAPSIZE@ 306EMACS_HEAPSIZE = @EMACS_HEAPSIZE@
305MINGW_TEMACS_POST_LINK = \
306 mv temacs$(EXEEXT) temacs.tmp; \
307 ../nt/addsection temacs.tmp temacs$(EXEEXT) EMHEAP $(EMACS_HEAPSIZE)
308 307
309UNEXEC_OBJ = @UNEXEC_OBJ@ 308UNEXEC_OBJ = @UNEXEC_OBJ@
310 309
@@ -326,7 +325,7 @@ MKDEPDIR=@MKDEPDIR@
326## 325##
327## FIXME? MYCPPFLAGS only referenced in etc/DEBUG. 326## FIXME? MYCPPFLAGS only referenced in etc/DEBUG.
328ALL_CFLAGS=-Demacs $(MYCPPFLAGS) -I. -I$(srcdir) \ 327ALL_CFLAGS=-Demacs $(MYCPPFLAGS) -I. -I$(srcdir) \
329 -I$(lib) -I$(srcdir)/../lib \ 328 -I$(lib) -I$(srcdir)/../lib $(C_HEAP_SWITCH) \
330 $(C_SWITCH_MACHINE) $(C_SWITCH_SYSTEM) $(C_SWITCH_X_SITE) \ 329 $(C_SWITCH_MACHINE) $(C_SWITCH_SYSTEM) $(C_SWITCH_X_SITE) \
331 $(GNUSTEP_CFLAGS) $(CFLAGS_SOUND) $(RSVG_CFLAGS) $(IMAGEMAGICK_CFLAGS) \ 330 $(GNUSTEP_CFLAGS) $(CFLAGS_SOUND) $(RSVG_CFLAGS) $(IMAGEMAGICK_CFLAGS) \
332 $(PNG_CFLAGS) $(LIBXML2_CFLAGS) $(DBUS_CFLAGS) \ 331 $(PNG_CFLAGS) $(LIBXML2_CFLAGS) $(DBUS_CFLAGS) \
diff --git a/src/buffer.c b/src/buffer.c
index 1f0bd3f0970..3cbb8153bc9 100644
--- a/src/buffer.c
+++ b/src/buffer.c
@@ -41,6 +41,10 @@ along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */
41#include "keymap.h" 41#include "keymap.h"
42#include "frame.h" 42#include "frame.h"
43 43
44#ifdef WINDOWSNT
45#include "w32heap.h" /* for mmap_* */
46#endif
47
44struct buffer *current_buffer; /* The current buffer. */ 48struct buffer *current_buffer; /* The current buffer. */
45 49
46/* First buffer in chain of all buffers (in reverse order of creation). 50/* First buffer in chain of all buffers (in reverse order of creation).
@@ -4632,7 +4636,8 @@ evaporate_overlays (ptrdiff_t pos)
4632 Allocation with mmap 4636 Allocation with mmap
4633 ***********************************************************************/ 4637 ***********************************************************************/
4634 4638
4635#ifdef USE_MMAP_FOR_BUFFERS 4639/* Note: WINDOWSNT implements this stuff on w32heap.c. */
4640#if defined USE_MMAP_FOR_BUFFERS && !defined WINDOWSNT
4636 4641
4637#include <sys/mman.h> 4642#include <sys/mman.h>
4638 4643
@@ -4774,36 +4779,6 @@ mmap_init (void)
4774 mmap_page_size = getpagesize (); 4779 mmap_page_size = getpagesize ();
4775} 4780}
4776 4781
4777/* Return a region overlapping address range START...END, or null if
4778 none. END is not including, i.e. the last byte in the range
4779 is at END - 1. */
4780
4781static struct mmap_region *
4782mmap_find (void *start, void *end)
4783{
4784 struct mmap_region *r;
4785 char *s = start, *e = end;
4786
4787 for (r = mmap_regions; r; r = r->next)
4788 {
4789 char *rstart = (char *) r;
4790 char *rend = rstart + r->nbytes_mapped;
4791
4792 if (/* First byte of range, i.e. START, in this region? */
4793 (s >= rstart && s < rend)
4794 /* Last byte of range, i.e. END - 1, in this region? */
4795 || (e > rstart && e <= rend)
4796 /* First byte of this region in the range? */
4797 || (rstart >= s && rstart < e)
4798 /* Last byte of this region in the range? */
4799 || (rend > s && rend <= e))
4800 break;
4801 }
4802
4803 return r;
4804}
4805
4806
4807/* Unmap a region. P is a pointer to the start of the user-araa of 4782/* Unmap a region. P is a pointer to the start of the user-araa of
4808 the region. */ 4783 the region. */
4809 4784
@@ -4880,38 +4855,6 @@ mmap_enlarge (struct mmap_region *r, int npages)
4880} 4855}
4881 4856
4882 4857
4883/* Set or reset variables holding references to mapped regions.
4884 If not RESTORE_P, set all variables to null. If RESTORE_P, set all
4885 variables to the start of the user-areas of mapped regions.
4886
4887 This function is called from Fdump_emacs to ensure that the dumped
4888 Emacs doesn't contain references to memory that won't be mapped
4889 when Emacs starts. */
4890
4891void
4892mmap_set_vars (bool restore_p)
4893{
4894 struct mmap_region *r;
4895
4896 if (restore_p)
4897 {
4898 mmap_regions = mmap_regions_1;
4899 mmap_fd = mmap_fd_1;
4900 for (r = mmap_regions; r; r = r->next)
4901 *r->var = MMAP_USER_AREA (r);
4902 }
4903 else
4904 {
4905 for (r = mmap_regions; r; r = r->next)
4906 *r->var = NULL;
4907 mmap_regions_1 = mmap_regions;
4908 mmap_regions = NULL;
4909 mmap_fd_1 = mmap_fd;
4910 mmap_fd = -1;
4911 }
4912}
4913
4914
4915/* Allocate a block of storage large enough to hold NBYTES bytes of 4858/* Allocate a block of storage large enough to hold NBYTES bytes of
4916 data. A pointer to the data is returned in *VAR. VAR is thus the 4859 data. A pointer to the data is returned in *VAR. VAR is thus the
4917 address of some variable which will use the data area. 4860 address of some variable which will use the data area.
diff --git a/src/emacs.c b/src/emacs.c
index 16d91de84a4..fabea11a3bf 100644
--- a/src/emacs.c
+++ b/src/emacs.c
@@ -2155,13 +2155,8 @@ You must run Emacs in batch mode in order to dump it. */)
2155 malloc_state_ptr = malloc_get_state (); 2155 malloc_state_ptr = malloc_get_state ();
2156#endif 2156#endif
2157 2157
2158#ifdef USE_MMAP_FOR_BUFFERS
2159 mmap_set_vars (0);
2160#endif
2161 unexec (SSDATA (filename), !NILP (symfile) ? SSDATA (symfile) : 0); 2158 unexec (SSDATA (filename), !NILP (symfile) ? SSDATA (symfile) : 0);
2162#ifdef USE_MMAP_FOR_BUFFERS 2159
2163 mmap_set_vars (1);
2164#endif
2165#ifdef DOUG_LEA_MALLOC 2160#ifdef DOUG_LEA_MALLOC
2166 free (malloc_state_ptr); 2161 free (malloc_state_ptr);
2167#endif 2162#endif
diff --git a/src/image.c b/src/image.c
index 07cf9f9af49..304603e7382 100644
--- a/src/image.c
+++ b/src/image.c
@@ -998,6 +998,11 @@ free_image (struct frame *f, struct image *img)
998 998
999 c->images[img->id] = NULL; 999 c->images[img->id] = NULL;
1000 1000
1001 /* Windows NT redefines 'free', but in this file, we need to
1002 avoid the redefinition. */
1003#ifdef WINDOWSNT
1004#undef free
1005#endif
1001 /* Free resources, then free IMG. */ 1006 /* Free resources, then free IMG. */
1002 img->type->free (f, img); 1007 img->type->free (f, img);
1003 xfree (img); 1008 xfree (img);
@@ -6453,7 +6458,6 @@ jpeg_file_src (j_decompress_ptr cinfo, FILE *fp)
6453 src->mgr.next_input_byte = NULL; 6458 src->mgr.next_input_byte = NULL;
6454} 6459}
6455 6460
6456
6457/* Load image IMG for use on frame F. Patterned after example.c 6461/* Load image IMG for use on frame F. Patterned after example.c
6458 from the JPEG lib. */ 6462 from the JPEG lib. */
6459 6463
diff --git a/src/lisp.h b/src/lisp.h
index 2fd28359868..62fca16ec38 100644
--- a/src/lisp.h
+++ b/src/lisp.h
@@ -72,7 +72,7 @@ DEFINE_GDB_SYMBOL_END (GCTYPEBITS)
72 2. We know malloc returns a multiple of 8. */ 72 2. We know malloc returns a multiple of 8. */
73#if (defined alignas \ 73#if (defined alignas \
74 && (defined GNU_MALLOC || defined DOUG_LEA_MALLOC || defined __GLIBC__ \ 74 && (defined GNU_MALLOC || defined DOUG_LEA_MALLOC || defined __GLIBC__ \
75 || defined DARWIN_OS || defined __sun)) 75 || defined DARWIN_OS || defined __sun || defined __MINGW32__))
76# define NONPOINTER_BITS 0 76# define NONPOINTER_BITS 0
77#else 77#else
78# define NONPOINTER_BITS GCTYPEBITS 78# define NONPOINTER_BITS GCTYPEBITS
diff --git a/src/unexw32.c b/src/unexw32.c
index f70cdd79478..60b926b2499 100644
--- a/src/unexw32.c
+++ b/src/unexw32.c
@@ -83,8 +83,6 @@ PCHAR bss_start_static = 0;
83DWORD_PTR bss_size_static = 0; 83DWORD_PTR bss_size_static = 0;
84DWORD_PTR extra_bss_size_static = 0; 84DWORD_PTR extra_bss_size_static = 0;
85 85
86PIMAGE_SECTION_HEADER heap_section;
87
88/* MinGW64 doesn't add a leading underscore to external symbols, 86/* MinGW64 doesn't add a leading underscore to external symbols,
89 whereas configure.ac sets up LD_SWITCH_SYSTEM_TEMACS to force the 87 whereas configure.ac sets up LD_SWITCH_SYSTEM_TEMACS to force the
90 entry point at __start, with two underscores. */ 88 entry point at __start, with two underscores. */
@@ -475,8 +473,6 @@ get_section_info (file_data *p_infile)
475 bss_section_static = 0; 473 bss_section_static = 0;
476 extra_bss_size_static = 0; 474 extra_bss_size_static = 0;
477 } 475 }
478
479 heap_section = rva_to_section (PTR_TO_RVA (get_heap_start ()), nt_header);
480} 476}
481 477
482 478
@@ -518,9 +514,11 @@ copy_executable_and_dump_data (file_data *p_infile,
518 if (verbose) \ 514 if (verbose) \
519 { \ 515 { \
520 printf ("%s\n", (message)); \ 516 printf ("%s\n", (message)); \
521 printf ("\t0x%08x Address in process.\n", s); \ 517 printf ("\t0x%p Address in process.\n", s); \
522 printf ("\t0x%08x Offset in output file.\n", dst - p_outfile->file_base); \ 518 printf ("\t0x%p Base output file.\n", p_outfile->file_base); \
523 printf ("\t0x%08x Size in bytes.\n", count); \ 519 printf ("\t0x%p Offset in output file.\n", dst - p_outfile->file_base); \
520 printf ("\t0x%p Address in output file.\n", dst); \
521 printf ("\t0x%p Size in bytes.\n", count); \
524 } \ 522 } \
525 memcpy (dst, s, count); \ 523 memcpy (dst, s, count); \
526 dst += count; \ 524 dst += count; \
@@ -629,34 +627,6 @@ copy_executable_and_dump_data (file_data *p_infile,
629 dst_section->Characteristics &= ~IMAGE_SCN_CNT_UNINITIALIZED_DATA; 627 dst_section->Characteristics &= ~IMAGE_SCN_CNT_UNINITIALIZED_DATA;
630 dst_section->Characteristics |= IMAGE_SCN_CNT_INITIALIZED_DATA; 628 dst_section->Characteristics |= IMAGE_SCN_CNT_INITIALIZED_DATA;
631 } 629 }
632 if (section == heap_section)
633 {
634 DWORD_PTR heap_start = (DWORD_PTR) get_heap_start ();
635 DWORD_PTR heap_size = get_committed_heap_size ();
636
637 /* Dump the used portion of the predump heap, adjusting the
638 section's size to the appropriate size. */
639 dst = dst_save
640 + RVA_TO_SECTION_OFFSET (PTR_TO_RVA (heap_start), dst_section);
641 COPY_PROC_CHUNK ("Dumping heap...", heap_start, heap_size,
642 be_verbose);
643 ROUND_UP_DST (dst_nt_header->OptionalHeader.FileAlignment);
644 dst_section->PointerToRawData = PTR_TO_OFFSET (dst_save, p_outfile);
645 /* Determine new size of raw data area. */
646 dst = max (dst, dst_save + dst_section->SizeOfRawData);
647 dst_section->SizeOfRawData = dst - dst_save;
648 /* Reduce the size of the heap section to fit (must be last
649 section). */
650 dst_nt_header->OptionalHeader.SizeOfImage -=
651 dst_section->Misc.VirtualSize
652 - ROUND_UP (dst_section->SizeOfRawData,
653 dst_nt_header->OptionalHeader.SectionAlignment);
654 dst_section->Misc.VirtualSize =
655 ROUND_UP (dst_section->SizeOfRawData,
656 dst_nt_header->OptionalHeader.SectionAlignment);
657 dst_section->Characteristics &= ~IMAGE_SCN_CNT_UNINITIALIZED_DATA;
658 dst_section->Characteristics |= IMAGE_SCN_CNT_INITIALIZED_DATA;
659 }
660 630
661 /* Align the section's raw data area. */ 631 /* Align the section's raw data area. */
662 ROUND_UP_DST (dst_nt_header->OptionalHeader.FileAlignment); 632 ROUND_UP_DST (dst_nt_header->OptionalHeader.FileAlignment);
@@ -767,9 +737,6 @@ unexec (const char *new_name, const char *old_name)
767 printf ("Dumping from %s\n", in_filename); 737 printf ("Dumping from %s\n", in_filename);
768 printf (" to %s\n", out_filename); 738 printf (" to %s\n", out_filename);
769 739
770 /* We need to round off our heap to NT's page size. */
771 round_heap (get_page_size ());
772
773 /* Open the undumped executable file. */ 740 /* Open the undumped executable file. */
774 if (!open_input_file (&in_file, in_filename)) 741 if (!open_input_file (&in_file, in_filename))
775 { 742 {
@@ -784,7 +751,6 @@ unexec (const char *new_name, const char *old_name)
784 /* The size of the dumped executable is the size of the original 751 /* The size of the dumped executable is the size of the original
785 executable plus the size of the heap and the size of the .bss section. */ 752 executable plus the size of the heap and the size of the .bss section. */
786 size = in_file.size + 753 size = in_file.size +
787 get_committed_heap_size () +
788 extra_bss_size + 754 extra_bss_size +
789 extra_bss_size_static; 755 extra_bss_size_static;
790 if (!open_output_file (&out_file, out_filename, size)) 756 if (!open_output_file (&out_file, out_filename, size))
@@ -799,6 +765,10 @@ unexec (const char *new_name, const char *old_name)
799 765
800 copy_executable_and_dump_data (&in_file, &out_file); 766 copy_executable_and_dump_data (&in_file, &out_file);
801 767
768 /* Unset it because it is plain wrong to keep it after dumping.
769 Malloc can still occur! */
770 using_dynamic_heap = FALSE;
771
802 /* Patch up header fields; profiler is picky about this. */ 772 /* Patch up header fields; profiler is picky about this. */
803 { 773 {
804 PIMAGE_DOS_HEADER dos_header; 774 PIMAGE_DOS_HEADER dos_header;
diff --git a/src/w32heap.c b/src/w32heap.c
index 8ab2f58c6e7..7cce7c50319 100644
--- a/src/w32heap.c
+++ b/src/w32heap.c
@@ -1,256 +1,611 @@
1/* Heap management routines for GNU Emacs on the Microsoft Windows API. 1/* Heap management routines for GNU Emacs on the Microsoft Windows
2 Copyright (C) 1994, 2001-2014 Free Software Foundation, Inc. 2 API. Copyright (C) 1994, 2001-2014 Free Software Foundation, Inc.
3 3
4This file is part of GNU Emacs. 4 This file is part of GNU Emacs.
5 5
6GNU Emacs is free software: you can redistribute it and/or modify 6 GNU Emacs is free software: you can redistribute it and/or modify
7it under the terms of the GNU General Public License as published by 7 it under the terms of the GNU General Public License as published by
8the Free Software Foundation, either version 3 of the License, or 8 the Free Software Foundation, either version 3 of the License, or
9(at your option) any later version. 9 (at your option) any later version.
10 10
11GNU Emacs is distributed in the hope that it will be useful, 11 GNU Emacs is distributed in the hope that it will be useful,
12but WITHOUT ANY WARRANTY; without even the implied warranty of 12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14GNU General Public License for more details. 14 GNU General Public License for more details.
15 15
16You should have received a copy of the GNU General Public License 16 You should have received a copy of the GNU General Public License
17along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */ 17 along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */
18 18
19/* 19/*
20 Geoff Voelker (voelker@cs.washington.edu) 7-29-94 20 Geoff Voelker (voelker@cs.washington.edu) 7-29-94
21*/ 21*/
22 22
23/*
24 Heavily modified by Fabrice Popineau (fabrice.popineau@gmail.com) 28-02-2014
25*/
26
27/*
28 Memory allocation scheme for w32/w64:
29
30 - Buffers are mmap'ed using a very simple emulation of mmap/munmap
31 - During the temacs phase:
32 * we use a private heap declared to be stored into the `dumped_data'
33 * unfortunately, this heap cannot be made growable, so the size of
34 blocks it can allocate is limited to (0x80000 - pagesize)
35 * the blocks that are larger than this are allocated from the end
36 of the `dumped_data' array; there are not so many of them.
37 We use a very simple first-fit scheme to reuse those blocks.
38 * we check that the private heap does not cross the area used
39 by the bigger chunks.
40 - During the emacs phase:
41 * we create a private heap for new memory blocks
42 * we make sure that we never free a block that has been dumped.
43 Freeing a dumped block could work in principle, but may prove
44 unreliable if we distribute binaries of emacs.exe: MS does not
45 guarantee that the heap data structures are the same across all
46 versions of their OS, even though the API is available since XP. */
47
23#include <config.h> 48#include <config.h>
24#include <stdio.h> 49#include <stdio.h>
25 50
51#include <sys/mman.h>
26#include "w32common.h" 52#include "w32common.h"
27#include "w32heap.h" 53#include "w32heap.h"
28#include "lisp.h" /* for VALMASK */ 54#include "lisp.h" /* for VALMASK */
29 55
30#define RVA_TO_PTR(rva) ((unsigned char *)((DWORD_PTR)(rva) + (DWORD_PTR)GetModuleHandle (NULL))) 56/* We chose to leave those declarations here. They are used only in
31 57 this file. The RtlCreateHeap is available since XP. It is located
32/* Emulate getpagesize. */ 58 in ntdll.dll and is available with the DDK. People often
33int 59 complained that HeapCreate doesn't offer the ability to create a
34getpagesize (void) 60 heap at a given place, which we need here, and which RtlCreateHeap
35{ 61 provides. We reproduce here the definitions available with the
36 return sysinfo_cache.dwPageSize; 62 DDK. */
37} 63
64typedef PVOID (WINAPI * RtlCreateHeap_Proc) (
65 /* _In_ */ ULONG Flags,
66 /* _In_opt_ */ PVOID HeapBase,
67 /* _In_opt_ */ SIZE_T ReserveSize,
68 /* _In_opt_ */ SIZE_T CommitSize,
69 /* _In_opt_ */ PVOID Lock,
70 /* _In_opt_ */ PVOID Parameters
71 );
72
73typedef LONG NTSTATUS;
74
75typedef NTSTATUS
76(NTAPI * PRTL_HEAP_COMMIT_ROUTINE)(
77 IN PVOID Base,
78 IN OUT PVOID *CommitAddress,
79 IN OUT PSIZE_T CommitSize
80 );
81
82typedef struct _RTL_HEAP_PARAMETERS {
83 ULONG Length;
84 SIZE_T SegmentReserve;
85 SIZE_T SegmentCommit;
86 SIZE_T DeCommitFreeBlockThreshold;
87 SIZE_T DeCommitTotalFreeThreshold;
88 SIZE_T MaximumAllocationSize;
89 SIZE_T VirtualMemoryThreshold;
90 SIZE_T InitialCommit;
91 SIZE_T InitialReserve;
92 PRTL_HEAP_COMMIT_ROUTINE CommitRoutine;
93 SIZE_T Reserved[ 2 ];
94} RTL_HEAP_PARAMETERS, *PRTL_HEAP_PARAMETERS;
95
96/* We reserve space for dumping emacs lisp byte-code inside a static
97 array. By storing it in an array, the generic mechanism in
98 unexecw32.c will be able to dump it without the need to add a
99 special segment to the executable. In order to be able to do this
100 without losing too much space, we need to create a Windows heap at
101 the specific address of the static array. The RtlCreateHeap
102 available inside the NT kernel since XP will do this. It allows to
103 create a non-growable heap at a specific address. So before
104 dumping, we create a non-growable heap at the address of the
105 dumped_data[] array. After dumping, we reuse memory allocated
106 there without being able to free it (but most of it is not meant to
107 be freed anyway), and we use a new private heap for all new
108 allocations. */
109
110unsigned char dumped_data[DUMPED_HEAP_SIZE];
38 111
39/* Info for managing our preload heap, which is essentially a fixed size 112/* Info for managing our preload heap, which is essentially a fixed size
40 data area in the executable. */ 113 data area in the executable. */
41PIMAGE_SECTION_HEADER preload_heap_section; 114/* Info for keeping track of our heap. */
42
43/* Info for keeping track of our heap. */
44unsigned char *data_region_base = NULL; 115unsigned char *data_region_base = NULL;
45unsigned char *data_region_end = NULL; 116unsigned char *data_region_end = NULL;
46unsigned char *real_data_region_end = NULL; 117static DWORD_PTR committed = 0;
47size_t reserved_heap_size = 0;
48 118
49/* The start of the data segment. */ 119/* The maximum block size that can be handled by a non-growable w32
50unsigned char * 120 heap is limited by the MaxBlockSize value below.
51get_data_start (void) 121
52{ 122 This point deserves and explanation.
53 return data_region_base; 123
54} 124 The W32 heap allocator can be used for a growable
125 heap or a non-growable one.
126
127 A growable heap is not compatible with a fixed base address for the
128 heap. Only a non-growable one is. One drawback of non-growable
129 heaps is that they can hold only objects smaller than a certain
130 size (the one defined below). Most of the largest blocks are GC'ed
131 before dumping. In any case and to be safe, we implement a simple
132 first-fit allocation algorithm starting at the end of the
133 dumped_data[] array like depicted below:
55 134
56/* The end of the data segment. */ 135 ----------------------------------------------
57unsigned char * 136 | | | |
58get_data_end (void) 137 | Private heap |-> <-| Big chunks |
138 | | | |
139 ----------------------------------------------
140 ^ ^ ^
141 dumped_data dumped_data bc_limit
142 + committed
143
144*/
145#define HEAP_ENTRY_SHIFT 3
146#define PAGE_SIZE 0x1000
147#define MaxBlockSize (0x80000 - PAGE_SIZE)
148
149#define MAX_BLOCKS 0x40
150
151static struct
59{ 152{
60 return data_region_end; 153 unsigned char *address;
61} 154 size_t size;
155 DWORD occupied;
156} blocks[MAX_BLOCKS];
157
158static DWORD blocks_number = 0;
159static unsigned char *bc_limit;
160
161/* Handle for the private heap:
162 - inside the dumped_data[] array before dump,
163 - outside of it after dump.
164*/
165HANDLE heap = NULL;
166
167/* We redirect the standard allocation functions. */
168malloc_fn the_malloc_fn;
169realloc_fn the_realloc_fn;
170free_fn the_free_fn;
62 171
63#if !USE_LSB_TAG 172/* It doesn't seem to be useful to allocate from a file mapping.
64static char * 173 It would be if the memory was shared.
65allocate_heap (void) 174 http://stackoverflow.com/questions/307060/what-is-the-purpose-of-allocating-pages-in-the-pagefile-with-createfilemapping */
175
176/* This is the function to commit memory when the heap allocator
177 claims for new memory. Before dumping, we allocate space
178 from the fixed size dumped_data[] array.
179*/
180NTSTATUS NTAPI
181dumped_data_commit (PVOID Base, PVOID *CommitAddress, PSIZE_T CommitSize)
66{ 182{
67 /* Try to get as much as possible of the address range from the end of 183 /* This is used before dumping.
68 the preload heap section up to the usable address limit. Since GNU 184
69 malloc can handle gaps in the memory it gets from sbrk, we can 185 The private heap is stored at dumped_data[] address.
70 simply set the sbrk pointer to the base of the new heap region. */ 186 We commit contiguous areas of the dumped_data array
71 DWORD_PTR base = 187 as requests arrive. */
72 ROUND_UP ((RVA_TO_PTR (preload_heap_section->VirtualAddress) 188 *CommitAddress = data_region_base + committed;
73 + preload_heap_section->Misc.VirtualSize), 189 committed += *CommitSize;
74 get_allocation_unit ()); 190 if (((unsigned char *)(*CommitAddress)) + *CommitSize >= bc_limit)
75 DWORD_PTR end = ((unsigned __int64)1) << VALBITS; /* 256MB */
76 void *ptr = NULL;
77
78 while (!ptr && (base < end))
79 { 191 {
80#ifdef _WIN64 192 /* Check that the private heap area does not overlap the big
81 reserved_heap_size = min(end - base, 0x4000000000ull); /* Limit to 256Gb */ 193 chunks area. */
82#else 194 fprintf(stderr,
83 reserved_heap_size = end - base; 195 "dumped_data_commit: memory exhausted.\nEnlarge dumped_data[]!\n");
84#endif 196 exit (-1);
85 ptr = VirtualAlloc ((void *) base,
86 get_reserved_heap_size (),
87 MEM_RESERVE,
88 PAGE_NOACCESS);
89 base += 0x00100000; /* 1MB increment */
90 } 197 }
91 198 return 0;
92 return ptr;
93} 199}
94#else /* USE_LSB_TAG */ 200
95static char * 201/* Heap creation. */
96allocate_heap (void) 202
203/* Under MinGW32, we want to turn on Low Fragmentation Heap for XP.
204 MinGW32 lacks those definitions. */
205#ifndef _W64
206typedef enum _HEAP_INFORMATION_CLASS {
207 HeapCompatibilityInformation
208} HEAP_INFORMATION_CLASS;
209
210typedef WINBASEAPI BOOL (WINAPI * HeapSetInformation_Proc)(HANDLE,HEAP_INFORMATION_CLASS,PVOID,SIZE_T);
211#endif
212
213void
214init_heap (void)
97{ 215{
98#ifdef _WIN64 216 if (using_dynamic_heap)
99 size_t size = 0x4000000000ull; /* start by asking for 32GB */ 217 {
100#else 218 unsigned long enable_lfh = 2;
101 /* We used to start with 2GB here, but on Windows 7 that would leave 219
102 too little room in the address space for threads started by 220 /* After dumping, use a new private heap. We explicitly enable
103 Windows on our behalf, e.g. when we pop up the file selection 221 the low fragmentation heap here, for the sake of pre Vista
104 dialog. */ 222 versions. Note: this will harnlessly fail on Vista and
105 size_t size = 0x68000000; /* start by asking for 1.7GB */ 223 later, whyere the low fragmentation heap is enabled by
224 default. It will also fail on pre-Vista versions when Emacs
225 is run under a debugger; set _NO_DEBUG_HEAP=1 in the
226 environment before starting GDB to get low fragmentation heap
227 on XP and older systems, for the price of losing "certain
228 heap debug options"; for the details see
229 http://msdn.microsoft.com/en-us/library/windows/desktop/aa366705%28v=vs.85%29.aspx. */
230 data_region_end = data_region_base;
231
232 /* Create the private heap. */
233 heap = HeapCreate(0, 0, 0);
234
235#ifndef _W64
236 /* Set the low-fragmentation heap for OS before XP and Windows
237 Server 2003. */
238 HMODULE hm_kernel32dll = LoadLibrary("kernel32.dll");
239 HeapSetInformation_Proc s_pfn_Heap_Set_Information = (HeapSetInformation_Proc) GetProcAddress(hm_kernel32dll, "HeapSetInformation");
240 if (s_pfn_Heap_Set_Information != NULL)
241 if (s_pfn_Heap_Set_Information ((PVOID) heap,
242 HeapCompatibilityInformation,
243 &enable_lfh, sizeof(enable_lfh)) == 0)
244 DebPrint (("Enabling Low Fragmentation Heap failed\n"));
106#endif 245#endif
107 void *ptr = NULL;
108 246
109 while (!ptr && size > 0x00100000) 247 the_malloc_fn = malloc_after_dump;
248 the_realloc_fn = realloc_after_dump;
249 the_free_fn = free_after_dump;
250 }
251 else
110 { 252 {
111 reserved_heap_size = size; 253 /* Find the RtlCreateHeap function. Headers for this function
112 ptr = VirtualAlloc (NULL, 254 are provided with the w32 ddk, but the function is available
113 get_reserved_heap_size (), 255 in ntdll.dll since XP. */
114 MEM_RESERVE, 256 HMODULE hm_ntdll = LoadLibrary ("ntdll.dll");
115 PAGE_NOACCESS); 257 RtlCreateHeap_Proc s_pfn_Rtl_Create_Heap
116 size -= 0x00800000; /* if failed, decrease request by 8MB */ 258 = (RtlCreateHeap_Proc) GetProcAddress (hm_ntdll, "RtlCreateHeap");
259 /* Specific parameters for the private heap. */
260 RTL_HEAP_PARAMETERS params;
261 ZeroMemory(&params, sizeof(params));
262 params.Length = sizeof(RTL_HEAP_PARAMETERS);
263
264 data_region_base = (unsigned char *)ROUND_UP (dumped_data, 0x1000);
265 data_region_end = bc_limit = dumped_data + DUMPED_HEAP_SIZE;
266
267 params.InitialCommit = committed = 0x1000;
268 params.InitialReserve = sizeof(dumped_data);
269 /* Use our own routine to commit memory from the dumped_data
270 array. */
271 params.CommitRoutine = &dumped_data_commit;
272
273 /* Create the private heap. */
274 heap = s_pfn_Rtl_Create_Heap (0, data_region_base, 0, 0, NULL, &params);
275 the_malloc_fn = malloc_before_dump;
276 the_realloc_fn = realloc_before_dump;
277 the_free_fn = free_before_dump;
117 } 278 }
118 279
119 return ptr; 280 /* Update system version information to match current system. */
281 cache_system_info ();
120} 282}
121#endif /* USE_LSB_TAG */
122 283
284#undef malloc
285#undef realloc
286#undef calloc
287#undef free
288
289/* FREEABLE_P checks if the block can be safely freed. */
290#define FREEABLE_P(addr) \
291 ((unsigned char *)(addr) < dumped_data \
292 || (unsigned char *)(addr) >= dumped_data + DUMPED_HEAP_SIZE)
123 293
124/* Emulate Unix sbrk. Note that ralloc.c expects the return value to
125 be the address of the _start_ (not end) of the new block in case of
126 success, and zero (not -1) in case of failure. */
127void * 294void *
128sbrk (ptrdiff_t increment) 295malloc_after_dump (size_t size)
129{ 296{
130 void *result; 297 /* Use the new private heap. */
131 ptrdiff_t size = increment; 298 void *p = HeapAlloc (heap, 0, size);
132 299
133 result = data_region_end; 300 /* After dump, keep track of the last allocated byte for sbrk(0). */
301 data_region_end = p + size - 1;
302 return p;
303}
134 304
135 /* If size is negative, shrink the heap by decommitting pages. */ 305void *
136 if (size < 0) 306malloc_before_dump (size_t size)
307{
308 void *p;
309
310 /* Before dumping. The private heap can handle only requests for
311 less than MaxBlockSize. */
312 if (size < MaxBlockSize)
313 {
314 /* Use the private heap if possible. */
315 p = HeapAlloc (heap, 0, size);
316 }
317 else
137 { 318 {
138 ptrdiff_t new_size; 319 /* Find the first big chunk that can hold the requested size. */
139 unsigned char *new_data_region_end; 320 int i = 0;
140 321
141 size = -size; 322 for (i = 0; i < blocks_number; i++)
142 323 {
143 /* Sanity checks. */ 324 if (blocks[i].occupied == 0 && blocks[i].size >= size)
144 if ((data_region_end - size) < data_region_base) 325 break;
145 return NULL; 326 }
146 327 if (i < blocks_number)
147 /* We can only decommit full pages, so allow for
148 partial deallocation [cga]. */
149 new_data_region_end = (data_region_end - size);
150 new_data_region_end = (unsigned char *)
151 ((DWORD_PTR) (new_data_region_end + syspage_mask) & ~syspage_mask);
152 new_size = real_data_region_end - new_data_region_end;
153 real_data_region_end = new_data_region_end;
154 if (new_size > 0)
155 { 328 {
156 /* Decommit size bytes from the end of the heap. */ 329 /* If found, use it. */
157 if (using_dynamic_heap 330 p = blocks[i].address;
158 && !VirtualFree (real_data_region_end, new_size, MEM_DECOMMIT)) 331 blocks[i].occupied = TRUE;
159 return NULL; 332 }
160 } 333 else
334 {
335 /* Allocate a new big chunk from the end of the dumped_data
336 array. */
337 if (blocks_number >= MAX_BLOCKS)
338 {
339 fprintf(stderr,
340 "malloc_before_dump: no more big chunks available.\nEnlarge MAX_BLOCKS!\n");
341 exit (-1);
342 }
343 bc_limit -= size;
344 bc_limit = (unsigned char *)ROUND_DOWN (bc_limit, 0x10);
345 p = bc_limit;
346 blocks[blocks_number].address = p;
347 blocks[blocks_number].size = size;
348 blocks[blocks_number].occupied = TRUE;
349 blocks_number++;
350 if (bc_limit < dumped_data + committed)
351 {
352 /* Check that areas do not overlap. */
353 fprintf(stderr,
354 "malloc_before_dump: memory exhausted.\nEnlarge dumped_data[]!\n");
355 exit (-1);
356 }
357 }
358 }
359 return p;
360}
361
362/* Re-allocate the previously allocated block in ptr, making the new
363 block SIZE bytes long. */
364void *
365realloc_after_dump (void *ptr, size_t size)
366{
367 void *p;
161 368
162 data_region_end -= size; 369 /* After dumping. */
370 if (FREEABLE_P (ptr))
371 {
372 /* Reallocate the block since it lies in the new heap. */
373 p = HeapReAlloc (heap, 0, ptr, size);
163 } 374 }
164 /* If size is positive, grow the heap by committing reserved pages. */ 375 else
165 else if (size > 0)
166 { 376 {
167 /* Sanity checks. */ 377 /* If the block lies in the dumped data, do not free it. Only
168 if ((data_region_end + size) > 378 allocate a new one. */
169 (data_region_base + get_reserved_heap_size ())) 379 p = HeapAlloc (heap, 0, size);
170 return NULL; 380 CopyMemory (p, ptr, size);
171
172 /* Commit more of our heap. */
173 if (using_dynamic_heap
174 && VirtualAlloc (data_region_end, size, MEM_COMMIT,
175 PAGE_READWRITE) == NULL)
176 return NULL;
177 data_region_end += size;
178
179 /* We really only commit full pages, so record where
180 the real end of committed memory is [cga]. */
181 real_data_region_end = (unsigned char *)
182 ((DWORD_PTR) (data_region_end + syspage_mask) & ~syspage_mask);
183 } 381 }
382 /* After dump, keep track of the last allocated byte for sbrk(0). */
383 data_region_end = p + size - 1;
384 return p;
385}
184 386
185 return result; 387void *
388realloc_before_dump (void *ptr, size_t size)
389{
390 void *p;
391
392 /* Before dumping. */
393 if (dumped_data < (unsigned char *)ptr
394 && (unsigned char *)ptr < bc_limit && size <= MaxBlockSize)
395 p = HeapReAlloc (heap, 0, ptr, size);
396 else
397 {
398 /* In this case, either the new block is too large for the heap,
399 or the old block was already too large. In both cases,
400 malloc_before_dump() and free_before_dump() will take care of
401 reallocation. */
402 p = malloc_before_dump (size);
403 CopyMemory (p, ptr, size);
404 free_before_dump (ptr);
405 }
406 return p;
186} 407}
187 408
188/* Initialize the internal heap variables used by sbrk. When running in 409/* Free a block allocated by `malloc', `realloc' or `calloc'. */
189 preload phase (ie. in the undumped executable), we rely entirely on a
190 fixed size heap section included in the .exe itself; this is
191 preserved during dumping, and truncated to the size actually used.
192
193 When running in the dumped executable, we reserve as much as possible
194 of the address range that is addressable by Lisp object pointers, to
195 supplement what is left of the preload heap. Although we cannot rely
196 on the dynamically allocated arena being contiguous with the static
197 heap area, it is not a problem because sbrk can pretend that the gap
198 was allocated by something else; GNU malloc detects when there is a
199 jump in the sbrk values, and starts a new heap block. */
200void 410void
201init_heap (void) 411free_after_dump (void *ptr)
202{ 412{
203 PIMAGE_DOS_HEADER dos_header; 413 /* After dumping. */
204 PIMAGE_NT_HEADERS nt_header; 414 if (FREEABLE_P (ptr))
205 415 {
206 dos_header = (PIMAGE_DOS_HEADER) RVA_TO_PTR (0); 416 /* Free the block if it is in the new private heap. */
207 nt_header = (PIMAGE_NT_HEADERS) (((DWORD_PTR) dos_header) + 417 HeapFree (heap, 0, ptr);
208 dos_header->e_lfanew); 418 }
209 preload_heap_section = find_section ("EMHEAP", nt_header); 419}
210 420
211 if (using_dynamic_heap) 421void
422free_before_dump (void *ptr)
423{
424 /* Before dumping. */
425 if (dumped_data < (unsigned char *)ptr
426 && (unsigned char *)ptr < bc_limit)
212 { 427 {
213 data_region_base = allocate_heap (); 428 /* Free the block if it is allocated in the private heap. */
214 if (!data_region_base) 429 HeapFree (heap, 0, ptr);
215 { 430 }
216 printf ("Error: Could not reserve dynamic heap area.\n"); 431 else
217 exit (1); 432 {
218 } 433 /* Look for the big chunk. */
434 int i;
219 435
220#if !USE_LSB_TAG 436 for(i = 0; i < blocks_number; i++)
221 /* Ensure that the addresses don't use the upper tag bits since
222 the Lisp type goes there. */
223 if (((DWORD_PTR) data_region_base & ~VALMASK) != 0)
224 { 437 {
225 printf ("Error: The heap was allocated in upper memory.\n"); 438 if (blocks[i].address == ptr)
226 exit (1); 439 {
440 /* Reset block occupation if found. */
441 blocks[i].occupied = 0;
442 break;
443 }
444 /* What if the block is not found? We should trigger an
445 error here. */
446 eassert (i < blocks_number);
227 } 447 }
228#endif
229 data_region_end = data_region_base;
230 real_data_region_end = data_region_end;
231 } 448 }
232 else 449}
450
451/* Emulate getpagesize. */
452int
453getpagesize (void)
454{
455 return sysinfo_cache.dwPageSize;
456}
457
458void *
459sbrk (ptrdiff_t increment)
460{
461 /* The data_region_end address is the one of the last byte
462 allocated. The sbrk() function is not emulated at all, except
463 for a 0 value of its parameter. This is needed by the emacs lisp
464 function `memory-limit'. */
465 return data_region_end;
466}
467
468#define MAX_BUFFER_SIZE (512 * 1024 * 1024)
469
470/* MMAP allocation for buffers. */
471void *
472mmap_alloc (void **var, size_t nbytes)
473{
474 void *p = NULL;
475
476 /* We implement amortized allocation. We start by reserving twice
477 the size requested and commit only the size requested. Then
478 realloc could proceed and use the reserved pages, reallocating
479 only if needed. Buffer shrink would happen only so that we stay
480 in the 2x range. This is a big win when visiting compressed
481 files, where the final size of the buffer is not known in
482 advance, and the buffer is enlarged several times as the data is
483 decompressed on the fly. */
484 if (nbytes < MAX_BUFFER_SIZE)
485 p = VirtualAlloc (NULL, (nbytes * 2), MEM_RESERVE, PAGE_READWRITE);
486
487 /* If it fails, or if the request is above 512MB, try with the
488 requested size. */
489 if (p == NULL)
490 p = VirtualAlloc (NULL, nbytes, MEM_RESERVE, PAGE_READWRITE);
491
492 if (p != NULL)
233 { 493 {
234 data_region_base = RVA_TO_PTR (preload_heap_section->VirtualAddress); 494 /* Now, commit pages for NBYTES. */
235 data_region_end = data_region_base; 495 *var = VirtualAlloc (p, nbytes, MEM_COMMIT, PAGE_READWRITE);
236 real_data_region_end = data_region_end;
237 reserved_heap_size = preload_heap_section->Misc.VirtualSize;
238 } 496 }
239 497
240 /* Update system version information to match current system. */ 498 if (!p && GetLastError () != ERROR_NOT_ENOUGH_MEMORY)
241 cache_system_info (); 499 DebPrint (("mmap_alloc: error %ld\n", GetLastError()));
500
501 return *var = p;
242} 502}
243 503
244/* Round the heap up to the given alignment. */
245void 504void
246round_heap (size_t align) 505mmap_free (void **var)
247{ 506{
248 DWORD_PTR needs_to_be; 507 if (*var)
249 DWORD_PTR need_to_alloc; 508 {
509 if (VirtualFree (*var, 0, MEM_RELEASE) == 0)
510 DebPrint (("mmap_free: error %ld\n", GetLastError()));
511 *var = NULL;
512 }
513}
250 514
251 needs_to_be = (DWORD_PTR) ROUND_UP (get_heap_end (), align); 515void *
252 need_to_alloc = needs_to_be - (DWORD_PTR) get_heap_end (); 516mmap_realloc (void **var, size_t nbytes)
517{
518 MEMORY_BASIC_INFORMATION memInfo, m2;
519
520 if (*var == NULL)
521 return mmap_alloc (var, nbytes);
522
523 /* This case happens in init_buffer(). */
524 if (nbytes == 0)
525 {
526 mmap_free (var);
527 return mmap_alloc (var, nbytes);
528 }
529
530 if (VirtualQuery (*var, &memInfo, sizeof (memInfo)) == 0)
531 DebPrint (("mmap_realloc: VirtualQuery error = %ld\n", GetLastError()));
532
533 /* We need to enlarge the block. */
534 if (memInfo.RegionSize < nbytes)
535 {
536 if (VirtualQuery (*var + memInfo.RegionSize, &m2, sizeof(m2)) == 0)
537 DebPrint (("mmap_realloc: VirtualQuery error = %ld\n", GetLastError()));
538 /* If there is enough room in the current reserved area, then
539 commit more pages as needed. */
540 if (m2.State == MEM_RESERVE
541 && nbytes <= memInfo.RegionSize + m2.RegionSize)
542 {
543 void *p;
544
545 p = VirtualAlloc (*var + memInfo.RegionSize,
546 nbytes - memInfo.RegionSize,
547 MEM_COMMIT, PAGE_READWRITE);
548 if (!p /* && GetLastError() != ERROR_NOT_ENOUGH_MEMORY */)
549 DebPrint (("realloc enlarge: VirtualAlloc error %ld\n",
550 GetLastError()));
551 return *var;
552 }
553 else
554 {
555 /* Else we must actually enlarge the block by allocating a
556 new one and copying previous contents from the old to the
557 new one. */
558 void *old_ptr = *var;
559
560 if (mmap_alloc (var, nbytes))
561 {
562 CopyMemory (*var, old_ptr, memInfo.RegionSize);
563 mmap_free (&old_ptr);
564 return *var;
565 }
566 else
567 {
568 /* We failed to enlarge the buffer. */
569 *var = old_ptr;
570 return NULL;
571 }
572 }
573 }
574
575 /* If we are shrinking by more than one page... */
576 if (memInfo.RegionSize > nbytes + getpagesize())
577 {
578 /* If we are shrinking a lot... */
579 if ((memInfo.RegionSize / 2) > nbytes)
580 {
581 /* Let's give some memory back to the system and release
582 some pages. */
583 void *old_ptr = *var;
584
585 if (mmap_alloc (var, nbytes))
586 {
587 CopyMemory (*var, old_ptr, nbytes);
588 mmap_free (&old_ptr);
589 return *var;
590 }
591 else
592 {
593 /* In case we fail to shrink, try to go on with the old block.
594 But that means there is a lot of memory pressure.
595 We could also decommit pages. */
596 *var = old_ptr;
597 return *var;
598 }
599 }
600
601 /* We still can decommit pages. */
602 if (VirtualFree (*var + nbytes + get_page_size(),
603 memInfo.RegionSize - nbytes - get_page_size(),
604 MEM_DECOMMIT) == 0)
605 DebPrint (("mmap_realloc: VirtualFree error %ld\n", GetLastError()));
606 return *var;
607 }
253 608
254 if (need_to_alloc) 609 /* Not enlarging, not shrinking by more than one page. */
255 sbrk (need_to_alloc); 610 return *var;
256} 611}
diff --git a/src/w32heap.h b/src/w32heap.h
index d5791a3a23c..84a26f958d0 100644
--- a/src/w32heap.h
+++ b/src/w32heap.h
@@ -27,15 +27,20 @@ along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>.
27/* 27/*
28 * Heap related stuff. 28 * Heap related stuff.
29 */ 29 */
30#define get_reserved_heap_size() reserved_heap_size 30
31#define get_committed_heap_size() (get_data_end () - get_data_start ()) 31#define DUMPED_HEAP_SIZE (HEAPSIZE*1024*1024)
32#define get_heap_start() get_data_start () 32
33#define get_heap_end() get_data_end () 33extern unsigned char dumped_data[];
34 34
35extern unsigned char *get_data_start (void); 35extern unsigned char *get_data_start (void);
36extern unsigned char *get_data_end (void); 36extern unsigned char *get_data_end (void);
37extern size_t reserved_heap_size; 37extern size_t reserved_heap_size;
38extern BOOL using_dynamic_heap; 38extern BOOL using_dynamic_heap;
39
40extern void *mmap_realloc (void **, size_t);
41extern void mmap_free (void **);
42extern void *mmap_alloc (void **, size_t);
43
39 44
40/* Emulation of Unix sbrk(). */ 45/* Emulation of Unix sbrk(). */
41extern void *sbrk (ptrdiff_t size); 46extern void *sbrk (ptrdiff_t size);
@@ -43,11 +48,8 @@ extern void *sbrk (ptrdiff_t size);
43/* Initialize heap structures for sbrk on startup. */ 48/* Initialize heap structures for sbrk on startup. */
44extern void init_heap (void); 49extern void init_heap (void);
45 50
46/* Round the heap to this size. */
47extern void round_heap (size_t size);
48
49/* ----------------------------------------------------------------- */ 51/* ----------------------------------------------------------------- */
50/* Useful routines for manipulating memory-mapped files. */ 52/* Useful routines for manipulating memory-mapped files. */
51 53
52typedef struct file_data { 54typedef struct file_data {
53 char *name; 55 char *name;
@@ -61,11 +63,11 @@ int open_input_file (file_data *p_file, char *name);
61int open_output_file (file_data *p_file, char *name, unsigned long size); 63int open_output_file (file_data *p_file, char *name, unsigned long size);
62void close_file_data (file_data *p_file); 64void close_file_data (file_data *p_file);
63 65
64/* Return pointer to section header for named section. */ 66/* Return pointer to section header for named section. */
65IMAGE_SECTION_HEADER * find_section (char * name, IMAGE_NT_HEADERS * nt_header); 67IMAGE_SECTION_HEADER * find_section (char * name, IMAGE_NT_HEADERS * nt_header);
66 68
67/* Return pointer to section header for section containing the given 69/* Return pointer to section header for section containing the given
68 relative virtual address. */ 70 relative virtual address. */
69IMAGE_SECTION_HEADER * rva_to_section (DWORD_PTR rva, IMAGE_NT_HEADERS * nt_header); 71IMAGE_SECTION_HEADER * rva_to_section (DWORD_PTR rva, IMAGE_NT_HEADERS * nt_header);
70 72
71#endif /* NTHEAP_H_ */ 73#endif /* NTHEAP_H_ */