diff options
| author | Fabrice Popineau | 2014-05-27 20:31:17 +0300 |
|---|---|---|
| committer | Eli Zaretskii | 2014-05-27 20:31:17 +0300 |
| commit | 587fd086a045f715932f886ecf31015932464ce6 (patch) | |
| tree | d8c647af107ef94318fd920a05da09af654ef1c9 | |
| parent | 0da7d35c6754b44d1ef4383e4a8ba9b98afc3a4c (diff) | |
| download | emacs-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-- | ChangeLog | 7 | ||||
| -rw-r--r-- | configure.ac | 22 | ||||
| -rw-r--r-- | etc/ChangeLog | 4 | ||||
| -rw-r--r-- | etc/NEWS | 5 | ||||
| -rw-r--r-- | nt/ChangeLog | 9 | ||||
| -rw-r--r-- | nt/INSTALL | 21 | ||||
| -rw-r--r-- | nt/inc/ms-w32.h | 33 | ||||
| -rw-r--r-- | nt/inc/sys/mman.h | 31 | ||||
| -rw-r--r-- | src/ChangeLog | 32 | ||||
| -rw-r--r-- | src/Makefile.in | 9 | ||||
| -rw-r--r-- | src/buffer.c | 69 | ||||
| -rw-r--r-- | src/emacs.c | 7 | ||||
| -rw-r--r-- | src/image.c | 6 | ||||
| -rw-r--r-- | src/lisp.h | 2 | ||||
| -rw-r--r-- | src/unexw32.c | 48 | ||||
| -rw-r--r-- | src/w32heap.c | 733 | ||||
| -rw-r--r-- | src/w32heap.h | 24 |
17 files changed, 720 insertions, 342 deletions
| @@ -1,3 +1,10 @@ | |||
| 1 | 2014-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 | |||
| 1 | 2014-05-27 Paul Eggert <eggert@cs.ucla.edu> | 8 | 2014-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 | |||
| 1973 | system_malloc=$emacs_cv_sanitize_address | 1973 | system_malloc=$emacs_cv_sanitize_address |
| 1974 | case "$opsys" in | 1974 | case "$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 ;; |
| 1977 | esac | 1977 | esac |
| 1978 | 1978 | ||
| 1979 | GMALLOC_OBJ= | 1979 | GMALLOC_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 |
| 2025 | fi | 2025 | fi |
| 2026 | 2026 | ||
| @@ -2030,7 +2030,7 @@ fi | |||
| 2030 | 2030 | ||
| 2031 | use_mmap_for_buffers=no | 2031 | use_mmap_for_buffers=no |
| 2032 | case "$opsys" in | 2032 | case "$opsys" in |
| 2033 | cygwin|freebsd|irix6-5) use_mmap_for_buffers=yes ;; | 2033 | cygwin|mingw32|freebsd|irix6-5) use_mmap_for_buffers=yes ;; |
| 2034 | esac | 2034 | esac |
| 2035 | 2035 | ||
| 2036 | AC_FUNC_MMAP | 2036 | AC_FUNC_MMAP |
| @@ -2046,6 +2046,7 @@ AC_CHECK_LIB(Xbsd, main, LD_SWITCH_X_SITE="$LD_SWITCH_X_SITE -lXbsd") | |||
| 2046 | 2046 | ||
| 2047 | dnl Check for the POSIX thread library. | 2047 | dnl Check for the POSIX thread library. |
| 2048 | LIB_PTHREAD= | 2048 | LIB_PTHREAD= |
| 2049 | if test "$opsys" != "mingw32"; then | ||
| 2049 | AC_CHECK_HEADERS_ONCE(pthread.h) | 2050 | AC_CHECK_HEADERS_ONCE(pthread.h) |
| 2050 | if test "$ac_cv_header_pthread_h"; then | 2051 | if 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 |
| 2067 | fi | 2068 | fi |
| 2068 | AC_SUBST([LIB_PTHREAD]) | 2069 | AC_SUBST([LIB_PTHREAD]) |
| 2070 | fi | ||
| 2069 | 2071 | ||
| 2070 | dnl Check for need for bigtoc support on IBM AIX | 2072 | dnl 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. |
| 4846 | TEMACS_POST_LINK=":" | 4846 | TEMACS_POST_LINK=":" |
| 4847 | ADDSECTION= | 4847 | ADDSECTION= |
| 4848 | EMACS_HEAPSIZE= | 4848 | C_HEAP_SWITCH= |
| 4849 | if test "${opsys}" = "mingw32"; then | 4849 | if 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 |
| 4857 | fi | 4857 | fi |
| 4858 | 4858 | ||
| 4859 | AC_SUBST(ADDSECTION) | 4859 | AC_SUBST(ADDSECTION) |
| 4860 | AC_SUBST(TEMACS_POST_LINK) | 4860 | AC_SUBST(TEMACS_POST_LINK) |
| 4861 | AC_SUBST(EMACS_HEAPSIZE) | 4861 | AC_SUBST(C_HEAP_SWITCH) |
| 4862 | 4862 | ||
| 4863 | ## Common for all window systems | 4863 | ## Common for all window systems |
| 4864 | if test "$window_system" != "none"; then | 4864 | if 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 @@ | |||
| 1 | 2014-05-27 Fabrice Popineau <fabrice.popineau@gmail.com> | ||
| 2 | |||
| 3 | * NEWS: Mention build changes on MS-Windows. | ||
| 4 | |||
| 1 | 2014-05-26 Paul Eggert <eggert@cs.ucla.edu> | 5 | 2014-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). |
| @@ -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. |
| 41 | Use './configure PKG_CONFIG=/full/name/of/pkg-config' if you need to. | 41 | Use './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 | ||
| 45 | or Windows Server 2003. The built binaries still run on all versions | ||
| 46 | of 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 @@ | |||
| 1 | 2014-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 | |||
| 1 | 2014-05-17 Paul Eggert <eggert@cs.ucla.edu> | 10 | 2014-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 | ||
| 7 | The MSYS/MinGW build described here is supported on versions of | 7 | The MSYS/MinGW build described here is supported on versions of |
| 8 | Windows starting with Windows 2000 and newer. Windows 9X are not | 8 | Windows starting with Windows XP and newer. Building on Windows 2000 |
| 9 | supported (but the Emacs binary produced by this build will run on | 9 | and Windows 9X is not supported (but the Emacs binary produced by this |
| 10 | Windows 9X as well). | 10 | build 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 | |
| 441 | typedef void * (* malloc_fn)(size_t); | ||
| 442 | typedef void * (* realloc_fn)(void *, size_t); | ||
| 443 | typedef void (* free_fn)(void *); | ||
| 444 | |||
| 445 | extern void *malloc_before_dump(size_t); | ||
| 446 | extern void *realloc_before_dump(void *, size_t); | ||
| 447 | extern void free_before_dump(void *); | ||
| 448 | extern void *malloc_after_dump(size_t); | ||
| 449 | extern void *realloc_after_dump(void *, size_t); | ||
| 450 | extern void free_after_dump(void *); | ||
| 451 | |||
| 452 | extern malloc_fn the_malloc_fn; | ||
| 453 | extern realloc_fn the_realloc_fn; | ||
| 454 | extern 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 | ||
| 12 | extern "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 @@ | |||
| 1 | 2014-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 | |||
| 1 | 2014-05-27 Paul Eggert <eggert@cs.ucla.edu> | 33 | 2014-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. |
| 87 | C_SWITCH_X_SITE=@C_SWITCH_X_SITE@ | 87 | C_SWITCH_X_SITE=@C_SWITCH_X_SITE@ |
| 88 | 88 | ||
| 89 | ## Set Emacs dumped heap size for Windows NT | ||
| 90 | C_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. |
| 302 | TEMACS_POST_LINK = @TEMACS_POST_LINK@ | 305 | TEMACS_POST_LINK = @TEMACS_POST_LINK@ |
| 303 | ADDSECTION = @ADDSECTION@ | ||
| 304 | EMACS_HEAPSIZE = @EMACS_HEAPSIZE@ | 306 | EMACS_HEAPSIZE = @EMACS_HEAPSIZE@ |
| 305 | MINGW_TEMACS_POST_LINK = \ | ||
| 306 | mv temacs$(EXEEXT) temacs.tmp; \ | ||
| 307 | ../nt/addsection temacs.tmp temacs$(EXEEXT) EMHEAP $(EMACS_HEAPSIZE) | ||
| 308 | 307 | ||
| 309 | UNEXEC_OBJ = @UNEXEC_OBJ@ | 308 | UNEXEC_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. |
| 328 | ALL_CFLAGS=-Demacs $(MYCPPFLAGS) -I. -I$(srcdir) \ | 327 | ALL_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 | |||
| 44 | struct buffer *current_buffer; /* The current buffer. */ | 48 | struct 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 | |||
| 4781 | static struct mmap_region * | ||
| 4782 | mmap_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 | |||
| 4891 | void | ||
| 4892 | mmap_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; | |||
| 83 | DWORD_PTR bss_size_static = 0; | 83 | DWORD_PTR bss_size_static = 0; |
| 84 | DWORD_PTR extra_bss_size_static = 0; | 84 | DWORD_PTR extra_bss_size_static = 0; |
| 85 | 85 | ||
| 86 | PIMAGE_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 | ||
| 4 | This file is part of GNU Emacs. | 4 | This file is part of GNU Emacs. |
| 5 | 5 | ||
| 6 | GNU Emacs is free software: you can redistribute it and/or modify | 6 | GNU Emacs is free software: you can redistribute it and/or modify |
| 7 | it 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 |
| 8 | the 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 | ||
| 11 | GNU Emacs is distributed in the hope that it will be useful, | 11 | GNU Emacs is distributed in the hope that it will be useful, |
| 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of | 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| 14 | GNU General Public License for more details. | 14 | GNU General Public License for more details. |
| 15 | 15 | ||
| 16 | You should have received a copy of the GNU General Public License | 16 | You should have received a copy of the GNU General Public License |
| 17 | along 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 |
| 33 | int | 59 | complained that HeapCreate doesn't offer the ability to create a |
| 34 | getpagesize (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 | |
| 64 | typedef 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 | |||
| 73 | typedef LONG NTSTATUS; | ||
| 74 | |||
| 75 | typedef NTSTATUS | ||
| 76 | (NTAPI * PRTL_HEAP_COMMIT_ROUTINE)( | ||
| 77 | IN PVOID Base, | ||
| 78 | IN OUT PVOID *CommitAddress, | ||
| 79 | IN OUT PSIZE_T CommitSize | ||
| 80 | ); | ||
| 81 | |||
| 82 | typedef 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 | |||
| 110 | unsigned 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. */ |
| 41 | PIMAGE_SECTION_HEADER preload_heap_section; | 114 | /* Info for keeping track of our heap. */ |
| 42 | |||
| 43 | /* Info for keeping track of our heap. */ | ||
| 44 | unsigned char *data_region_base = NULL; | 115 | unsigned char *data_region_base = NULL; |
| 45 | unsigned char *data_region_end = NULL; | 116 | unsigned char *data_region_end = NULL; |
| 46 | unsigned char *real_data_region_end = NULL; | 117 | static DWORD_PTR committed = 0; |
| 47 | size_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 |
| 50 | unsigned char * | 120 | heap is limited by the MaxBlockSize value below. |
| 51 | get_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 | ---------------------------------------------- |
| 57 | unsigned char * | 136 | | | | | |
| 58 | get_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 | |||
| 151 | static 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 | |||
| 158 | static DWORD blocks_number = 0; | ||
| 159 | static 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 | */ | ||
| 165 | HANDLE heap = NULL; | ||
| 166 | |||
| 167 | /* We redirect the standard allocation functions. */ | ||
| 168 | malloc_fn the_malloc_fn; | ||
| 169 | realloc_fn the_realloc_fn; | ||
| 170 | free_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. |
| 64 | static char * | 173 | It would be if the memory was shared. |
| 65 | allocate_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 | */ | ||
| 180 | NTSTATUS NTAPI | ||
| 181 | dumped_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 | |
| 95 | static char * | 201 | /* Heap creation. */ |
| 96 | allocate_heap (void) | 202 | |
| 203 | /* Under MinGW32, we want to turn on Low Fragmentation Heap for XP. | ||
| 204 | MinGW32 lacks those definitions. */ | ||
| 205 | #ifndef _W64 | ||
| 206 | typedef enum _HEAP_INFORMATION_CLASS { | ||
| 207 | HeapCompatibilityInformation | ||
| 208 | } HEAP_INFORMATION_CLASS; | ||
| 209 | |||
| 210 | typedef WINBASEAPI BOOL (WINAPI * HeapSetInformation_Proc)(HANDLE,HEAP_INFORMATION_CLASS,PVOID,SIZE_T); | ||
| 211 | #endif | ||
| 212 | |||
| 213 | void | ||
| 214 | init_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(¶ms, 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, ¶ms); | ||
| 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. */ | ||
| 127 | void * | 294 | void * |
| 128 | sbrk (ptrdiff_t increment) | 295 | malloc_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. */ | 305 | void * |
| 136 | if (size < 0) | 306 | malloc_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. */ | ||
| 364 | void * | ||
| 365 | realloc_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; | 387 | void * |
| 388 | realloc_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. */ | ||
| 200 | void | 410 | void |
| 201 | init_heap (void) | 411 | free_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) | 421 | void |
| 422 | free_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. */ | ||
| 452 | int | ||
| 453 | getpagesize (void) | ||
| 454 | { | ||
| 455 | return sysinfo_cache.dwPageSize; | ||
| 456 | } | ||
| 457 | |||
| 458 | void * | ||
| 459 | sbrk (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. */ | ||
| 471 | void * | ||
| 472 | mmap_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. */ | ||
| 245 | void | 504 | void |
| 246 | round_heap (size_t align) | 505 | mmap_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); | 515 | void * |
| 252 | need_to_alloc = needs_to_be - (DWORD_PTR) get_heap_end (); | 516 | mmap_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 () | 33 | extern unsigned char dumped_data[]; |
| 34 | 34 | ||
| 35 | extern unsigned char *get_data_start (void); | 35 | extern unsigned char *get_data_start (void); |
| 36 | extern unsigned char *get_data_end (void); | 36 | extern unsigned char *get_data_end (void); |
| 37 | extern size_t reserved_heap_size; | 37 | extern size_t reserved_heap_size; |
| 38 | extern BOOL using_dynamic_heap; | 38 | extern BOOL using_dynamic_heap; |
| 39 | |||
| 40 | extern void *mmap_realloc (void **, size_t); | ||
| 41 | extern void mmap_free (void **); | ||
| 42 | extern void *mmap_alloc (void **, size_t); | ||
| 43 | |||
| 39 | 44 | ||
| 40 | /* Emulation of Unix sbrk(). */ | 45 | /* Emulation of Unix sbrk(). */ |
| 41 | extern void *sbrk (ptrdiff_t size); | 46 | extern 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. */ |
| 44 | extern void init_heap (void); | 49 | extern void init_heap (void); |
| 45 | 50 | ||
| 46 | /* Round the heap to this size. */ | ||
| 47 | extern 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 | ||
| 52 | typedef struct file_data { | 54 | typedef struct file_data { |
| 53 | char *name; | 55 | char *name; |
| @@ -61,11 +63,11 @@ int open_input_file (file_data *p_file, char *name); | |||
| 61 | int open_output_file (file_data *p_file, char *name, unsigned long size); | 63 | int open_output_file (file_data *p_file, char *name, unsigned long size); |
| 62 | void close_file_data (file_data *p_file); | 64 | void 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. */ |
| 65 | IMAGE_SECTION_HEADER * find_section (char * name, IMAGE_NT_HEADERS * nt_header); | 67 | IMAGE_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. */ |
| 69 | IMAGE_SECTION_HEADER * rva_to_section (DWORD_PTR rva, IMAGE_NT_HEADERS * nt_header); | 71 | IMAGE_SECTION_HEADER * rva_to_section (DWORD_PTR rva, IMAGE_NT_HEADERS * nt_header); |
| 70 | 72 | ||
| 71 | #endif /* NTHEAP_H_ */ | 73 | #endif /* NTHEAP_H_ */ |