]> code.delx.au - gnu-emacs/commitdiff
Merge from origin/emacs-24
authorFabián Ezequiel Gallina <fgallina@gnu.org>
Wed, 28 Jan 2015 03:09:39 +0000 (00:09 -0300)
committerFabián Ezequiel Gallina <fgallina@gnu.org>
Wed, 28 Jan 2015 03:09:39 +0000 (00:09 -0300)
a012c7b Fix copyright years by hand
732fd4c Update copyright year to 2015

Conflicts:
INSTALL.REPO
admin/notes/lel-TODO
doc/man/grep-changelog.1
doc/misc/eww.texi
etc/CONTRIBUTE
etc/GNU
etc/NEWS
etc/refcards/emacsver.tex
etc/refcards/ru-refcard.tex
lib-src/grep-changelog
lib-src/test-distrib.c
lib/alloca.in.h
lib/binary-io.h
lib/c-ctype.h
lib/c-strcasecmp.c
lib/c-strncasecmp.c
lib/careadlinkat.c
lib/close-stream.c
lib/dosname.h
lib/dup2.c
lib/filemode.h
lib/fpending.c
lib/fpending.h
lib/getgroups.c
lib/getloadavg.c
lib/getopt.in.h
lib/getopt1.c
lib/getopt_int.h
lib/gettext.h
lib/gettime.c
lib/gettimeofday.c
lib/group-member.c
lib/md5.c
lib/md5.h
lib/memrchr.c
lib/sha1.c
lib/sig2str.c
lib/stdarg.in.h
lib/stdbool.in.h
lib/stdlib.in.h
lib/strftime.c
lib/strtoimax.c
lib/strtol.c
lib/strtoll.c
lib/strtoull.c
lib/tempname.c
lib/time_r.c
lib/unsetenv.c
lib/xalloc-oversized.h
lisp/gnus/gnus-setup.el
lisp/progmodes/cap-words.el
lisp/w32-common-fns.el
m4/alloca.m4
m4/dup2.m4
m4/filemode.m4
m4/getgroups.m4
m4/getloadavg.m4
m4/gettime.m4
m4/gettimeofday.m4
m4/gnulib-common.m4
m4/group-member.m4
m4/manywarnings.m4
m4/memrchr.m4
m4/mktime.m4
m4/pathmax.m4
m4/pthread_sigmask.m4
m4/sig2str.m4
m4/ssize_t.m4
m4/st_dm_mode.m4
m4/stat-time.m4
m4/stdarg.m4
m4/stdbool.m4
m4/stddef_h.m4
m4/stdio_h.m4
m4/strftime.m4
m4/strtoimax.m4
m4/strtoll.m4
m4/strtoull.m4
m4/strtoumax.m4
m4/time_h.m4
m4/timer_time.m4
m4/timespec.m4
m4/unistd_h.m4
m4/utimbuf.m4
nextstep/README
nt/addsection.c
src/insdel.c
src/w32heap.c
test/automated/package-x-test.el

1  2 
INSTALL.REPO
doc/misc/eww.texi
doc/misc/info.texi
lib/stdlib.in.h
src/insdel.c
src/w32heap.c

diff --combined INSTALL.REPO
index 3431ee480bf212f9a1de18f3eb5e90f4db84f114,e26d3672552d0f2f5ae17a1be80fd3fbd3d40d55..61b16340d351abbf194861871db525fd4ba737b3
@@@ -1,10 -1,9 +1,14 @@@
+ Copyright (C) 2002-2015 Free Software Foundation, Inc.
+ See the end of the file for license conditions.
             Building and Installing Emacs from the Repository
  
 +Simply run 'make'.  This should work if your files are freshly checked
 +out from the repository, and if you have the proper tools installed.
 +If it doesn't work, or if you have special build requirements, the
 +following information may be helpful.
 +
  Building Emacs from the source-code repository requires some tools
  that are not needed when building from a release.  You will need:
  
@@@ -12,37 -11,51 +16,37 @@@ autoconf  - at least the version specif
    configure.ac (in the AC_PREREQ command).
  automake  - at least the version specified near the start of
    configure.ac (in the AM_INIT_AUTOMAKE command).
 +git - at least Git 1.7.1.  If your repository was created by an older
 +  Git version, you may need to reclone it.
  makeinfo  - not strictly necessary, but highly recommended, so that
    you can build the manuals.
  
 -The `autogen.sh' script can help you figure out if you have the
 -necessary tools.
 -
 -The first time you build, there are a couple of extra steps.
 -First, generate the `configure' script and some related files:
 +To use the autotools, run the following shell command to generate the
 +'configure' script and some related files:
  
    $ ./autogen.sh
  
 -(or you can just run `autoreconf -i -I m4').
 -
 -You can then configure your build (use `./configure --help' to see
 -options you can set):
 +You can then configure your build as follows:
  
    $ ./configure
  
 -If you want later builds to go faster, at the expense of sometimes
 -doing the wrong thing if you update the build procedure, you can
 -invoke "./configure -C" instead.
 -
 -Some of the files that are included in the Emacs tarball, such as
 -byte-compiled Lisp files, are not stored in the repository.  Therefore, to
 -build from the repository you must run "make bootstrap" instead of
 -just "make":
 -
 -  $ make bootstrap
 -
 -Normally, it is not necessary to use "make bootstrap" after every
 -update from the repository.  "make" should work in 90% of the cases and be
 -much quicker.
 +The 'configure' script has many options; run './configure --help' to
 +see them.  For example, if you want later builds to go faster, albeit
 +sometimes doing the wrong thing if you update the build procedure, you
 +can invoke './configure -C'.  After configuring, build Emacs as follows:
  
    $ make
  
 -(If you want to install the Emacs binary, type "make install" instead
 -of "make" in the last command.)
 +If you want to install Emacs, type 'make install' instead of 'make' in
 +the last command.
  
 -Occasionally the file "lisp/loaddefs.el" (and similar automatically
 -generated files, such as esh-groups.el, and *-loaddefs.el in some
 -subdirectories of lisp/, e.g. mh-e/ and calendar/) will need to be
 +Occasionally the file 'lisp/loaddefs.el' (and similar automatically
 +generated files, such as 'esh-groups.el', and '*-loaddefs.el' in some
 +subdirectories of 'lisp/', e.g., 'mh-e/' and 'calendar/') will need to be
  updated to reflect new autoloaded functions.  If you see errors (rather
  than warnings) about undefined lisp functions during compilation, that
  may be the reason.  Finally, sometimes there can be build failures
 -related to *loaddefs.el (e.g. "required feature `esh-groups' was not
 +related to '*loaddefs.el' (e.g., "required feature `esh-groups' was not
  provided").  In that case, follow the instructions below.
  
  To update loaddefs.el (and similar files), do:
    $ cd lisp
    $ make autoloads
  
 -If either of the above partial procedures fails, try "make bootstrap".
 -If CPU time is not an issue, the most thorough way to rebuild, and
 -avoid any spurious problems, is always to use this method.
 -
 -Users of non-Posix systems (MS-Windows etc.) should run the
 -platform-specific configuration scripts (nt/configure.bat, config.bat,
 -etc.) before "make bootstrap" or "make"; the rest of the procedure is
 -applicable to those systems as well.
 +If either of the above partial procedures fails, try 'make bootstrap'.
 +If CPU time is not an issue, 'make bootstrap' is the most thorough way
 +to rebuild, and avoid any spurious problems.
  
  Because the repository version of Emacs is a work in progress, it will
  sometimes fail to build.  Please wait a day or so (and check the
@@@ -64,8 -82,6 +68,8 @@@ never platform-specific
  
  
  \f
 +Copyright (C) 2002-2015 Free Software Foundation, Inc.
 +
  This file is part of GNU Emacs.
  
  GNU Emacs is free software: you can redistribute it and/or modify
diff --combined doc/misc/eww.texi
index 8c1865d78a5f959c4b3b1b2243bbac57fca9f1e7,7762158cb0fdd6682a5685fffa098d48c0e61509..fd9f6f543e04d2f6c5ad6dd4a98280c9a92f4993
@@@ -1,6 -1,6 +1,6 @@@
  \input texinfo @c -*-texinfo-*-
  @c %**start of header
 -@setfilename ../../info/eww
 +@setfilename ../../info/eww.info
  @settitle Emacs Web Wowser
  @documentencoding UTF-8
  @c %**end of header
@@@ -8,7 -8,7 +8,7 @@@
  @copying
  This file documents the GNU Emacs Web Wowser (EWW) package.
  
- Copyright @copyright{} 2014-2015 Free Software Foundation, Inc.
+ Copyright @copyright{} 2014--2015 Free Software Foundation, Inc.
  
  @quotation
  Permission is granted to copy, distribute and/or modify this document
@@@ -97,12 -97,6 +97,12 @@@ and the web page is rendered in it.  Yo
  web page hit @kbd{g} (@code{eww-reload}).  Pressing @kbd{w}
  (@code{eww-copy-page-url}) will copy the current URL to the kill ring.
  
 +@findex eww-readable
 +@kindex R
 +  The @kbd{R} command (@code{eww-readable}) will attempt to determine
 +which part of the document contains the ``readable'' text, and will
 +only display this part.  This usually gets rid of menus and the like.
 +
  @findex eww-download
  @vindex eww-download-directory
  @kindex d
@@@ -126,21 -120,6 +126,21 @@@ history press @kbd{H} (@code{eww-list-h
  buffer @file{*eww history*}.  The history is lost when EWW is quit.
  If you want to remember websites you can use bookmarks.
  
 +@vindex eww-history-limit
 +  Along with the URLs visited, EWW also remembers both the rendered
 +page (as it appears in the buffer) and its source.  This can take a
 +considerable amount of memory, so EWW discards the history entries to
 +keep their number within a set limit, as specified by
 +@code{eww-history-limit}; the default being 50.  This variable could
 +also be set to @code{nil} to allow for the history list to grow
 +indefinitely.
 +
 +@cindex PDF
 +  PDFs are viewed inline, by default, with @code{doc-view-mode}, but
 +this can be customized by using the mailcap (@pxref{mailcap,,,
 +emacs-mime, Emacs MIME Manual})
 +mechanism, in particular @code{mailcap-mime-data}.
 +
  @findex eww-add-bookmark
  @findex eww-list-bookmarks
  @kindex b
@@@ -152,13 -131,6 +152,13 @@@ You can view stored bookmarks with @kbd
  (@code{eww-list-bookmarks}).  This will open the bookmark buffer
  @file{*eww bookmarks*}.
  
 +@findex eww-list-buffers
 +@kindex S
 +@cindex Multiple Buffers
 +  To get summary of currently opened EWW buffers, press @kbd{S}
 +(@code{eww-list-buffers}).  The @file{*eww buffers*} buffer allows to
 +quickly kill, flip through and switch to specific EWW buffer.
 +
  @findex eww-browse-with-external-browser
  @vindex shr-external-browser
  @vindex eww-use-external-browser-for-content-type
@@@ -232,40 -204,6 +232,40 @@@ contrast.  If that is still too low fo
  variables @code{shr-color-visible-distance-min} and
  @code{shr-color-visible-luminance-min} to get a better contrast.
  
 +@cindex Desktop Support
 +@cindex Saving Sessions
 +  In addition to maintaining the history at run-time, EWW will also
 +save the partial state of its buffers (the URIs and the titles of the
 +pages visited) in the desktop file if one is used.  @xref{Saving Emacs
 +Sessions, , emacs, The GNU Emacs Manual}.
 +
 +@vindex eww-desktop-remove-duplicates
 +  EWW history may sensibly contain multiple entries for the same page
 +URI.  At run-time, these entries may still have different associated
 +point positions or the actual Web page contents.
 +The latter, however, tend to be overly large to preserve in the
 +desktop file, so they get omitted, thus rendering the respective
 +entries entirely equivalent.  By default, such duplicate entries are
 +not saved.  Setting @code{eww-desktop-remove-duplicates} to nil will
 +force EWW to save them anyway.
 +
 +@vindex eww-restore-desktop
 +  Restoring EWW buffers' contents may prove to take too long to
 +finish.  When the @code{eww-restore-desktop} variable is set to
 +@code{nil} (the default), EWW will not try to reload the last visited
 +Web page when the buffer is restored from the desktop file, thus
 +allowing for faster Emacs start-up times.  When set to @code{t},
 +restoring the buffers will also initiate the reloading of such pages.
 +
 +@vindex eww-restore-reload-prompt
 +  The EWW buffer restored from the desktop file but not yet reloaded
 +will contain a prompt, as specified by the
 +@code{eww-restore-reload-prompt} variable.  The value of this variable
 +will be passed through @code{substitute-command-keys} upon each use,
 +thus allowing for the use of the usual substitutions, such as
 +@code{\[eww-reload]} for the current key binding of the
 +@code{eww-reload} command.
 +
  @node History and Acknowledgments
  @appendix History and Acknowledgments
  
@@@ -291,11 -229,6 +291,11 @@@ developers started contributing to it a
  @node Variable Index
  @unnumbered Variable Index
  
 +@vindex eww-after-render-hook
 +After eww has rendered the data in the buffer,
 +@code{eww-after-render-hook} is called.  It can be used to alter the
 +contents, for instance.
 +
  @printindex vr
  
  @node Lisp Function Index
diff --combined doc/misc/info.texi
index 0e2e64f2356dafd387418ac0c45029d9352af616,62567ebedd8c0128e8f9aa8d1c597a3e2e14b0cd..759956d21dc19e39206727679aa922ffaf42880c
@@@ -15,7 -15,7 +15,7 @@@
  This file describes how to use Info, the menu-driven GNU
  documentation system.
  
- Copyright @copyright{} 1989, 1992, 1996--2014 Free Software Foundation, Inc.
+ Copyright @copyright{} 1989, 1992, 1996--2015 Free Software Foundation, Inc.
  
  @quotation
  Permission is granted to copy, distribute and/or modify this document
@@@ -1151,10 -1151,7 +1151,10 @@@ switches to the buffer @file{*info*<2>}
    If you have created many Info buffers in Emacs, you might find it
  difficult to remember which buffer is showing which manual.  You can
  use the command @kbd{M-x info-display-manual} to show an Info manual
 -by name, reusing an existing buffer if there is one.
 +by name, reusing an existing buffer if there is one.  When given a
 +prefix argument, this command limits the completion alternatives to
 +currently visited info files, thus giving a convenient way to switch
 +between several manuals.
  
  @node Emacs Info Variables
  @section Emacs Info-mode Variables
diff --combined lib/stdlib.in.h
index 428a119188c84d331314eb2d0cb66faa028452d1,502622d5ac34b5465ffd1174fed9f209bd387082..490be4629faf9cd377414c808f66cb870da551f9
@@@ -1,6 -1,7 +1,7 @@@
  /* A GNU-like <stdlib.h>.
  
-    Copyright (C) 1995, 2001-2004, 2006-2015 Free Software Foundation, Inc.
+    Copyright (C) 1995, 2001-2004, 2006-2015 Free Software Foundation,
+    Inc.
  
     This program is free software: you can redistribute it and/or modify
     it under the terms of the GNU General Public License as published by
@@@ -520,29 -521,6 +521,29 @@@ _GL_CXXALIAS_SYS (putenv, int, (char *s
  _GL_CXXALIASWARN (putenv);
  #endif
  
 +#if @GNULIB_QSORT_R@
 +# if @REPLACE_QSORT_R@
 +#  if !(defined __cplusplus && defined GNULIB_NAMESPACE)
 +#   undef qsort_r
 +#   define qsort_r rpl_qsort_r
 +#  endif
 +_GL_FUNCDECL_RPL (qsort_r, void, (void *base, size_t nmemb, size_t size,
 +                                  int (*compare) (void const *, void const *,
 +                                                  void *),
 +                                  void *arg) _GL_ARG_NONNULL ((1, 4)));
 +_GL_CXXALIAS_RPL (qsort_r, void, (void *base, size_t nmemb, size_t size,
 +                                  int (*compare) (void const *, void const *,
 +                                                  void *),
 +                                  void *arg));
 +# else
 +_GL_CXXALIAS_SYS (qsort_r, void, (void *base, size_t nmemb, size_t size,
 +                                  int (*compare) (void const *, void const *,
 +                                                  void *),
 +                                  void *arg));
 +# endif
 +_GL_CXXALIASWARN (qsort_r);
 +#endif
 +
  
  #if @GNULIB_RANDOM_R@
  # if !@HAVE_RANDOM_R@
diff --combined src/insdel.c
index 3b5b520aac8331816b866741c97c36e8692815aa,086bdb756b24b787c6b0cdc4e8957199b77e938c..80650be25aeb9c2fa4ad0f3993024a8761be19d1
@@@ -1,7 -1,6 +1,6 @@@
  /* Buffer insertion/deletion and gap motion for GNU Emacs.
- Copyright (C) 1985-1986, 1993-1995, 1997-2015 Free Software Foundation,
- Inc.
+    Copyright (C) 1985-1986, 1993-1995, 1997-2015 Free Software
+    Foundation, Inc.
  
  This file is part of GNU Emacs.
  
@@@ -52,6 -51,8 +51,6 @@@ static Lisp_Object combine_after_change
  /* Buffer which combine_after_change_list is about.  */
  static Lisp_Object combine_after_change_buffer;
  
 -Lisp_Object Qinhibit_modification_hooks;
 -
  static void signal_before_change (ptrdiff_t, ptrdiff_t, ptrdiff_t *);
  
  /* Also used in marker.c to enable expensive marker checks.  */
@@@ -202,25 -203,6 +201,25 @@@ gap_right (ptrdiff_t charpos, ptrdiff_
    QUIT;
  }
  \f
 +/* If the selected window's old pointm is adjacent or covered by the
 +   region from FROM to TO, unsuspend auto hscroll in that window.  */
 +
 +static void
 +adjust_suspend_auto_hscroll (ptrdiff_t from, ptrdiff_t to)
 +{
 +  if (WINDOWP (selected_window))
 +    {
 +      struct window *w = XWINDOW (selected_window);
 +
 +      if (BUFFERP (w->contents)
 +        && XBUFFER (w->contents) == current_buffer
 +        && XMARKER (w->old_pointm)->charpos >= from
 +        && XMARKER (w->old_pointm)->charpos <= to)
 +      w->suspend_auto_hscroll = 0;
 +    }
 +}
 +
 +
  /* Adjust all markers for a deletion
     whose range in bytes is FROM_BYTE to TO_BYTE.
     The range in charpos is FROM to TO.
@@@ -235,7 -217,6 +234,7 @@@ adjust_markers_for_delete (ptrdiff_t fr
    struct Lisp_Marker *m;
    ptrdiff_t charpos;
  
 +  adjust_suspend_auto_hscroll (from, to);
    for (m = BUF_MARKERS (current_buffer); m; m = m->next)
      {
        charpos = m->charpos;
@@@ -275,7 -256,6 +274,7 @@@ adjust_markers_for_insert (ptrdiff_t fr
    ptrdiff_t nchars = to - from;
    ptrdiff_t nbytes = to_byte - from_byte;
  
 +  adjust_suspend_auto_hscroll (from, to);
    for (m = BUF_MARKERS (current_buffer); m; m = m->next)
      {
        eassert (m->bytepos >= m->charpos
@@@ -341,7 -321,6 +340,7 @@@ adjust_markers_for_replace (ptrdiff_t f
    ptrdiff_t diff_chars = new_chars - old_chars;
    ptrdiff_t diff_bytes = new_bytes - old_bytes;
  
 +  adjust_suspend_auto_hscroll (from, from + old_chars);
    for (m = BUF_MARKERS (current_buffer); m; m = m->next)
      {
        if (m->bytepos >= prev_to_byte)
@@@ -722,7 -701,7 +721,7 @@@ count_combining_after (const unsigned c
        (2) POS is the last of the current buffer.
        (3) A character at POS can't be a following byte of multibyte
            character.  */
 -  if (length > 0 && ASCII_BYTE_P (string[length - 1])) /* case (1) */
 +  if (length > 0 && ASCII_CHAR_P (string[length - 1])) /* case (1) */
      return 0;
    if (pos_byte == Z_BYTE)     /* case (2) */
      return 0;
@@@ -1201,10 -1180,10 +1200,10 @@@ adjust_after_replace (ptrdiff_t from, p
  
    /* Update various buffer positions for the new text.  */
    GAP_SIZE -= len_byte;
 -  ZV += len; Z+= len;
 +  ZV += len; Z += len;
    ZV_BYTE += len_byte; Z_BYTE += len_byte;
    GPT += len; GPT_BYTE += len_byte;
 -  if (GAP_SIZE > 0) *(GPT_ADDR) = 0; /* Put an anchor. */
 +  if (GAP_SIZE > 0) *(GPT_ADDR) = 0; /* Put an anchor.  */
  
    if (nchars_del > 0)
      adjust_markers_for_replace (from, from_byte, nchars_del, nbytes_del,
    if (from < PT)
      adjust_point (len - nchars_del, len_byte - nbytes_del);
  
 -  /* As byte combining will decrease Z, we must check this again. */
 +  /* As byte combining will decrease Z, we must check this again.  */
    if (Z - GPT < END_UNCHANGED)
      END_UNCHANGED = Z - GPT;
  
@@@ -1598,7 -1577,7 +1597,7 @@@ del_range_byte (ptrdiff_t from_byte, pt
  {
    ptrdiff_t from, to;
  
 -  /* Make args be valid */
 +  /* Make args be valid */
    if (from_byte < BEGV_BYTE)
      from_byte = BEGV_BYTE;
    if (to_byte > ZV_BYTE)
@@@ -1680,7 -1659,7 +1679,7 @@@ del_range_both (ptrdiff_t from, ptrdiff
  /* Delete a range of text, specified both as character positions
     and byte positions.  FROM and TO are character positions,
     while FROM_BYTE and TO_BYTE are byte positions.
 -   If RET_STRING, the deleted area is returned as a string. */
 +   If RET_STRING, the deleted area is returned as a string.  */
  
  Lisp_Object
  del_range_2 (ptrdiff_t from, ptrdiff_t from_byte,
@@@ -1779,6 -1758,8 +1778,6 @@@ modify_text (ptrdiff_t start, ptrdiff_
    bset_point_before_scroll (current_buffer, Qnil);
  }
  
 -Lisp_Object Qregion_extract_function;
 -
  /* Check that it is okay to modify the buffer between START and END,
     which are char positions.
  
@@@ -1794,11 -1775,9 +1793,11 @@@ prepare_to_modify_buffer_1 (ptrdiff_t s
                            ptrdiff_t *preserve_ptr)
  {
    struct buffer *base_buffer;
 +  Lisp_Object temp;
  
 +  XSETFASTINT (temp, start);
    if (!NILP (BVAR (current_buffer, read_only)))
 -    Fbarf_if_buffer_read_only ();
 +    Fbarf_if_buffer_read_only (temp);
  
    bset_redisplay (current_buffer);
  
    else
      base_buffer = current_buffer;
  
 -#ifdef CLASH_DETECTION
 +  if (inhibit_modification_hooks)
 +    return;
 +
    if (!NILP (BVAR (base_buffer, file_truename))
        /* Make binding buffer-file-name to nil effective.  */
        && !NILP (BVAR (base_buffer, filename))
        && SAVE_MODIFF >= MODIFF)
      lock_file (BVAR (base_buffer, file_truename));
 -#else
 -  /* At least warn if this file has changed on disk since it was visited.  */
 -  if (!NILP (BVAR (base_buffer, filename))
 -      && SAVE_MODIFF >= MODIFF
 -      && NILP (Fverify_visited_file_modtime (Fcurrent_buffer ()))
 -      && !NILP (Ffile_exists_p (BVAR (base_buffer, filename))))
 -    call1 (intern ("ask-user-about-supersession-threat"),
 -         BVAR (base_buffer,filename));
 -#endif /* not CLASH_DETECTION */
  
    /* If `select-active-regions' is non-nil, save the region text.  */
    /* FIXME: Move this to Elisp (via before-change-functions).  */
    if (!NILP (BVAR (current_buffer, mark_active))
 -      && !inhibit_modification_hooks
        && XMARKER (BVAR (current_buffer, mark))->buffer
        && NILP (Vsaved_region_selection)
        && (EQ (Vselect_active_regions, Qonly)
@@@ -1975,6 -1962,9 +1974,6 @@@ signal_before_change (ptrdiff_t start_i
    ptrdiff_t count = SPECPDL_INDEX ();
    struct rvoe_arg rvoe_arg;
  
 -  if (inhibit_modification_hooks)
 -    return;
 -
    start = make_number (start_int);
    end = make_number (end_int);
    preserve_marker = Qnil;
    specbind (Qinhibit_modification_hooks, Qt);
  
    /* If buffer is unmodified, run a special hook for that case.  The
 -   check for Vfirst_change_hook is just a minor optimization. */
 +   check for Vfirst_change_hook is just a minor optimization.  */
    if (SAVE_MODIFF >= MODIFF
        && !NILP (Vfirst_change_hook))
      {
        PRESERVE_VALUE;
        PRESERVE_START_END;
 -      Frun_hooks (1, &Qfirst_change_hook);
 +      run_hook (Qfirst_change_hook);
      }
  
    /* Now run the before-change-functions if any.  */
    if (!NILP (Vbefore_change_functions))
      {
 -      Lisp_Object args[3];
        rvoe_arg.location = &Vbefore_change_functions;
        rvoe_arg.errorp = 1;
  
        record_unwind_protect_ptr (reset_var_on_error, &rvoe_arg);
  
        /* Actually run the hook functions.  */
 -      args[0] = Qbefore_change_functions;
 -      args[1] = FETCH_START;
 -      args[2] = FETCH_END;
 -      Frun_hook_with_args (3, args);
 +      CALLN (Frun_hook_with_args, Qbefore_change_functions,
 +           FETCH_START, FETCH_END);
  
        /* There was no error: unarm the reset_on_error.  */
        rvoe_arg.errorp = 0;
@@@ -2076,6 -2069,7 +2075,6 @@@ signal_after_change (ptrdiff_t charpos
  
    if (!NILP (Vafter_change_functions))
      {
 -      Lisp_Object args[4];
        rvoe_arg.location = &Vafter_change_functions;
        rvoe_arg.errorp = 1;
  
        record_unwind_protect_ptr (reset_var_on_error, &rvoe_arg);
  
        /* Actually run the hook functions.  */
 -      args[0] = Qafter_change_functions;
 -      XSETFASTINT (args[1], charpos);
 -      XSETFASTINT (args[2], charpos + lenins);
 -      XSETFASTINT (args[3], lendel);
 -      Frun_hook_with_args (4, args);
 +      CALLN (Frun_hook_with_args, Qafter_change_functions,
 +           make_number (charpos), make_number (charpos + lenins),
 +           make_number (lendel));
  
        /* There was no error: unarm the reset_on_error.  */
        rvoe_arg.errorp = 0;
diff --combined src/w32heap.c
index d5a9dae0aa42e9724e586232f2b881ac8f6b92e6,3b4738fcf46b1af1350b276db2981d0097e9a0e6..ee0eb161502e448f80e1931d7d9b0375f7f406f3
- /* Heap management routines for GNU Emacs on the Microsoft Windows
-    API.  Copyright (C) 1994, 2001-2015 Free Software Foundation, Inc.
+ /* Heap management routines for GNU Emacs on the Microsoft Windows API.
+    Copyright (C) 1994, 2001-2015 Free Software Foundation, Inc.
  
 -This file is part of GNU Emacs.
 +   This file is part of GNU Emacs.
  
 -GNU Emacs is free software: you can redistribute it and/or modify
 -it under the terms of the GNU General Public License as published by
 -the Free Software Foundation, either version 3 of the License, or
 -(at your option) any later version.
 +   GNU Emacs is free software: you can redistribute it and/or modify
 +   it under the terms of the GNU General Public License as published by
 +   the Free Software Foundation, either version 3 of the License, or
 +   (at your option) any later version.
  
 -GNU Emacs is distributed in the hope that it will be useful,
 -but WITHOUT ANY WARRANTY; without even the implied warranty of
 -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 -GNU General Public License for more details.
 +   GNU Emacs is distributed in the hope that it will be useful,
 +   but WITHOUT ANY WARRANTY; without even the implied warranty of
 +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 +   GNU General Public License for more details.
  
 -You should have received a copy of the GNU General Public License
 -along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.  */
 +   You should have received a copy of the GNU General Public License
 +   along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>. */
  
  /*
 -   Geoff Voelker (voelker@cs.washington.edu)                       7-29-94
 +  Geoff Voelker (voelker@cs.washington.edu)                          7-29-94
  */
  
 +/*
 +  Heavily modified by Fabrice Popineau (fabrice.popineau@gmail.com) 28-02-2014
 +*/
 +
 +/*
 +  Memory allocation scheme for w32/w64:
 +
 +  - Buffers are mmap'ed using a very simple emulation of mmap/munmap
 +  - During the temacs phase:
 +    * we use a private heap declared to be stored into the `dumped_data'
 +    * unfortunately, this heap cannot be made growable, so the size of
 +      blocks it can allocate is limited to (0x80000 - pagesize)
 +    * the blocks that are larger than this are allocated from the end
 +      of the `dumped_data' array; there are not so many of them.
 +      We use a very simple first-fit scheme to reuse those blocks.
 +    * we check that the private heap does not cross the area used
 +      by the bigger chunks.
 +  - During the emacs phase:
 +    * we create a private heap for new memory blocks
 +    * we make sure that we never free a block that has been dumped.
 +      Freeing a dumped block could work in principle, but may prove
 +      unreliable if we distribute binaries of emacs.exe: MS does not
 +      guarantee that the heap data structures are the same across all
 +      versions of their OS, even though the API is available since XP.  */
 +
  #include <config.h>
  #include <stdio.h>
 +#include <errno.h>
  
 +#include <sys/mman.h>
  #include "w32common.h"
  #include "w32heap.h"
  #include "lisp.h"  /* for VALMASK */
  
 -#define RVA_TO_PTR(rva) ((unsigned char *)((DWORD_PTR)(rva) + (DWORD_PTR)GetModuleHandle (NULL)))
 -
 -/* Emulate getpagesize.  */
 -int
 -getpagesize (void)
 -{
 -  return sysinfo_cache.dwPageSize;
 -}
 +/* We chose to leave those declarations here.  They are used only in
 +   this file.  The RtlCreateHeap is available since XP.  It is located
 +   in ntdll.dll and is available with the DDK.  People often
 +   complained that HeapCreate doesn't offer the ability to create a
 +   heap at a given place, which we need here, and which RtlCreateHeap
 +   provides.  We reproduce here the definitions available with the
 +   DDK.  */
 +
 +typedef PVOID (WINAPI * RtlCreateHeap_Proc) (
 +                                             /* _In_ */      ULONG Flags,
 +                                             /* _In_opt_ */  PVOID HeapBase,
 +                                             /* _In_opt_ */  SIZE_T ReserveSize,
 +                                             /* _In_opt_ */  SIZE_T CommitSize,
 +                                             /* _In_opt_ */  PVOID Lock,
 +                                             /* _In_opt_ */  PVOID Parameters
 +                                             );
 +
 +typedef LONG NTSTATUS;
 +
 +typedef NTSTATUS
 +(NTAPI * PRTL_HEAP_COMMIT_ROUTINE)(
 +                                   IN PVOID Base,
 +                                   IN OUT PVOID *CommitAddress,
 +                                   IN OUT PSIZE_T CommitSize
 +                                   );
 +
 +typedef struct _RTL_HEAP_PARAMETERS {
 +  ULONG Length;
 +  SIZE_T SegmentReserve;
 +  SIZE_T SegmentCommit;
 +  SIZE_T DeCommitFreeBlockThreshold;
 +  SIZE_T DeCommitTotalFreeThreshold;
 +  SIZE_T MaximumAllocationSize;
 +  SIZE_T VirtualMemoryThreshold;
 +  SIZE_T InitialCommit;
 +  SIZE_T InitialReserve;
 +  PRTL_HEAP_COMMIT_ROUTINE CommitRoutine;
 +  SIZE_T Reserved[ 2 ];
 +} RTL_HEAP_PARAMETERS, *PRTL_HEAP_PARAMETERS;
 +
 +/* We reserve space for dumping emacs lisp byte-code inside a static
 +   array.  By storing it in an array, the generic mechanism in
 +   unexecw32.c will be able to dump it without the need to add a
 +   special segment to the executable.  In order to be able to do this
 +   without losing too much space, we need to create a Windows heap at
 +   the specific address of the static array.  The RtlCreateHeap
 +   available inside the NT kernel since XP will do this.  It allows to
 +   create a non-growable heap at a specific address.  So before
 +   dumping, we create a non-growable heap at the address of the
 +   dumped_data[] array.  After dumping, we reuse memory allocated
 +   there without being able to free it (but most of it is not meant to
 +   be freed anyway), and we use a new private heap for all new
 +   allocations.  */
 +
 +/* FIXME: Most of the space reserved for dumped_data[] is only used by
 +   the 1st bootstrap-emacs.exe built while bootstrapping.  Once the
 +   preloaded Lisp files are byte-compiled, the next loadup uses less
 +   than half of the size stated below.  It would be nice to find a way
 +   to build only the first bootstrap-emacs.exe with the large size,
 +   and reset that to a lower value afterwards.  */
 +#if defined _WIN64 || defined WIDE_EMACS_INT
 +# define DUMPED_HEAP_SIZE (18*1024*1024)
 +#else
 +# define DUMPED_HEAP_SIZE (11*1024*1024)
 +#endif
  
 -/* Info for managing our preload heap, which is essentially a fixed size
 -   data area in the executable.  */
 -PIMAGE_SECTION_HEADER preload_heap_section;
 +static unsigned char dumped_data[DUMPED_HEAP_SIZE];
  
 -/* Info for keeping track of our heap.  */
 +/* Info for keeping track of our dynamic heap used after dumping. */
  unsigned char *data_region_base = NULL;
  unsigned char *data_region_end = NULL;
 -unsigned char *real_data_region_end = NULL;
 -size_t  reserved_heap_size = 0;
 +static DWORD_PTR committed = 0;
  
 -/* The start of the data segment.  */
 -unsigned char *
 -get_data_start (void)
 -{
 -  return data_region_base;
 -}
 +/* The maximum block size that can be handled by a non-growable w32
 +   heap is limited by the MaxBlockSize value below.
 +
 +   This point deserves and explanation.
 +
 +   The W32 heap allocator can be used for a growable
 +   heap or a non-growable one.
 +
 +   A growable heap is not compatible with a fixed base address for the
 +   heap.  Only a non-growable one is.  One drawback of non-growable
 +   heaps is that they can hold only objects smaller than a certain
 +   size (the one defined below).  Most of the largest blocks are GC'ed
 +   before dumping.  In any case and to be safe, we implement a simple
 +   first-fit allocation algorithm starting at the end of the
 +   dumped_data[] array like depicted below:
 +
 +  ----------------------------------------------
 +  |               |              |             |
 +  | Private heap  |->          <-|  Big chunks |
 +  |               |              |             |
 +  ----------------------------------------------
 +  ^               ^              ^
 +  dumped_data     dumped_data    bc_limit
 +                  + committed
  
 -/* The end of the data segment.  */
 -unsigned char *
 -get_data_end (void)
 +*/
 +
 +/* Info for managing our preload heap, which is essentially a fixed size
 +   data area in the executable. */
 +#define PAGE_SIZE 0x1000
 +#define MaxBlockSize (0x80000 - PAGE_SIZE)
 +
 +#define MAX_BLOCKS 0x40
 +
 +static struct
  {
 -  return data_region_end;
 -}
 +  unsigned char *address;
 +  size_t size;
 +  DWORD occupied;
 +} blocks[MAX_BLOCKS];
 +
 +static DWORD          blocks_number = 0;
 +static unsigned char *bc_limit;
 +
 +/* Handle for the private heap:
 +    - inside the dumped_data[] array before dump,
 +    - outside of it after dump.
 +*/
 +HANDLE heap = NULL;
  
 -#if !USE_LSB_TAG
 -static char *
 -allocate_heap (void)
 +/* We redirect the standard allocation functions.  */
 +malloc_fn the_malloc_fn;
 +realloc_fn the_realloc_fn;
 +free_fn the_free_fn;
 +
 +/* It doesn't seem to be useful to allocate from a file mapping.
 +   It would be if the memory was shared.
 +     http://stackoverflow.com/questions/307060/what-is-the-purpose-of-allocating-pages-in-the-pagefile-with-createfilemapping  */
 +
 +/* This is the function to commit memory when the heap allocator
 +   claims for new memory.  Before dumping, we allocate space
 +   from the fixed size dumped_data[] array.
 +*/
 +NTSTATUS NTAPI
 +dumped_data_commit (PVOID Base, PVOID *CommitAddress, PSIZE_T CommitSize)
  {
 -  /* Try to get as much as possible of the address range from the end of
 -     the preload heap section up to the usable address limit.  Since GNU
 -     malloc can handle gaps in the memory it gets from sbrk, we can
 -     simply set the sbrk pointer to the base of the new heap region.  */
 -  DWORD_PTR base =
 -    ROUND_UP ((RVA_TO_PTR (preload_heap_section->VirtualAddress)
 -             + preload_heap_section->Misc.VirtualSize),
 -            get_allocation_unit ());
 -  DWORD_PTR end  = ((unsigned __int64)1) << VALBITS; /* 256MB */
 -  void *ptr = NULL;
 -
 -  while (!ptr && (base < end))
 +  /* This is used before dumping.
 +
 +     The private heap is stored at dumped_data[] address.
 +     We commit contiguous areas of the dumped_data array
 +     as requests arrive.  */
 +  *CommitAddress = data_region_base + committed;
 +  committed += *CommitSize;
 +  /* Check that the private heap area does not overlap the big chunks area.  */
 +  if (((unsigned char *)(*CommitAddress)) + *CommitSize >= bc_limit)
      {
 -#ifdef _WIN64
 -      reserved_heap_size = min(end - base, 0x4000000000ull); /* Limit to 256Gb */
 -#else
 -      reserved_heap_size = end - base;
 -#endif
 -      ptr = VirtualAlloc ((void *) base,
 -                        get_reserved_heap_size (),
 -                        MEM_RESERVE,
 -                        PAGE_NOACCESS);
 -      base += 0x00100000;  /* 1MB increment */
 +      fprintf (stderr,
 +             "dumped_data_commit: memory exhausted.\nEnlarge dumped_data[]!\n");
 +      exit (-1);
      }
 -
 -  return ptr;
 +  return 0;
  }
 -#else  /* USE_LSB_TAG */
 -static char *
 -allocate_heap (void)
 +
 +/* Heap creation.  */
 +
 +/* We want to turn on Low Fragmentation Heap for XP and older systems.
 +   MinGW32 lacks those definitions.  */
 +#ifndef MINGW_W64
 +typedef enum _HEAP_INFORMATION_CLASS {
 +  HeapCompatibilityInformation
 +} HEAP_INFORMATION_CLASS;
 +
 +typedef WINBASEAPI BOOL (WINAPI * HeapSetInformation_Proc)(HANDLE,HEAP_INFORMATION_CLASS,PVOID,SIZE_T);
 +#endif
 +
 +void
 +init_heap (void)
  {
 -#ifdef _WIN64
 -  size_t size = 0x4000000000ull; /* start by asking for 256GB */
 -#else
 -  /* We used to start with 2GB here, but on Windows 7 that would leave
 -     too little room in the address space for threads started by
 -     Windows on our behalf, e.g. when we pop up the file selection
 -     dialog.  */
 -  size_t size = 0x68000000; /* start by asking for 1.7GB */
 +  if (using_dynamic_heap)
 +    {
 +      unsigned long enable_lfh = 2;
 +
 +      /* After dumping, use a new private heap.  We explicitly enable
 +         the low fragmentation heap (LFH) here, for the sake of pre
 +         Vista versions.  Note: this will harmlessly fail on Vista and
 +         later, where the low-fragmentation heap is enabled by
 +         default.  It will also fail on pre-Vista versions when Emacs
 +         is run under a debugger; set _NO_DEBUG_HEAP=1 in the
 +         environment before starting GDB to get low fragmentation heap
 +         on XP and older systems, for the price of losing "certain
 +         heap debug options"; for the details see
 +         http://msdn.microsoft.com/en-us/library/windows/desktop/aa366705%28v=vs.85%29.aspx.  */
 +      data_region_end = data_region_base;
 +
 +      /* Create the private heap.  */
 +      heap = HeapCreate (0, 0, 0);
 +
 +#ifndef MINGW_W64
 +      /* Set the low-fragmentation heap for OS before Vista.  */
 +      HMODULE hm_kernel32dll = LoadLibrary ("kernel32.dll");
 +      HeapSetInformation_Proc s_pfn_Heap_Set_Information = (HeapSetInformation_Proc) GetProcAddress (hm_kernel32dll, "HeapSetInformation");
 +      if (s_pfn_Heap_Set_Information != NULL)
 +      {
 +        if (s_pfn_Heap_Set_Information ((PVOID) heap,
 +                                        HeapCompatibilityInformation,
 +                                        &enable_lfh, sizeof(enable_lfh)) == 0)
 +          DebPrint (("Enabling Low Fragmentation Heap failed: error %ld\n",
 +                     GetLastError ()));
 +      }
  #endif
 -  void *ptr = NULL;
  
 -  while (!ptr && size >= 0x00800000)
 +      the_malloc_fn = malloc_after_dump;
 +      the_realloc_fn = realloc_after_dump;
 +      the_free_fn = free_after_dump;
 +    }
 +  else
      {
 -      reserved_heap_size = size;
 -      ptr = VirtualAlloc (NULL,
 -                        get_reserved_heap_size (),
 -                        MEM_RESERVE,
 -                        PAGE_NOACCESS);
 -      size -= 0x00800000; /* if failed, decrease request by 8MB */
 +      /* Find the RtlCreateHeap function.  Headers for this function
 +         are provided with the w32 ddk, but the function is available
 +         in ntdll.dll since XP.  */
 +      HMODULE hm_ntdll = LoadLibrary ("ntdll.dll");
 +      RtlCreateHeap_Proc s_pfn_Rtl_Create_Heap
 +      = (RtlCreateHeap_Proc) GetProcAddress (hm_ntdll, "RtlCreateHeap");
 +      /* Specific parameters for the private heap.  */
 +      RTL_HEAP_PARAMETERS params;
 +      ZeroMemory (&params, sizeof(params));
 +      params.Length = sizeof(RTL_HEAP_PARAMETERS);
 +
 +      data_region_base = (unsigned char *)ROUND_UP (dumped_data, 0x1000);
 +      data_region_end = bc_limit = dumped_data + DUMPED_HEAP_SIZE;
 +
 +      params.InitialCommit = committed = 0x1000;
 +      params.InitialReserve = sizeof(dumped_data);
 +      /* Use our own routine to commit memory from the dumped_data
 +         array.  */
 +      params.CommitRoutine = &dumped_data_commit;
 +
 +      /* Create the private heap.  */
 +      if (s_pfn_Rtl_Create_Heap == NULL)
 +      {
 +        fprintf (stderr, "Cannot build Emacs without RtlCreateHeap being available; exiting.\n");
 +        exit (-1);
 +      }
 +      heap = s_pfn_Rtl_Create_Heap (0, data_region_base, 0, 0, NULL, &params);
 +      the_malloc_fn = malloc_before_dump;
 +      the_realloc_fn = realloc_before_dump;
 +      the_free_fn = free_before_dump;
      }
  
 -  return ptr;
 +  /* Update system version information to match current system.  */
 +  cache_system_info ();
  }
 -#endif /* USE_LSB_TAG */
  
 +#undef malloc
 +#undef realloc
 +#undef free
 +
 +/* FREEABLE_P checks if the block can be safely freed.  */
 +#define FREEABLE_P(addr)                                        \
 +    ((unsigned char *)(addr) < dumped_data                      \
 +     || (unsigned char *)(addr) >= dumped_data + DUMPED_HEAP_SIZE)
  
 -/* Emulate Unix sbrk.  Note that ralloc.c expects the return value to
 -   be the address of the _start_ (not end) of the new block in case of
 -   success, and zero (not -1) in case of failure.  */
  void *
 -sbrk (ptrdiff_t increment)
 +malloc_after_dump (size_t size)
  {
 -  void *result;
 -  ptrdiff_t size = increment;
 +  /* Use the new private heap.  */
 +  void *p = HeapAlloc (heap, 0, size);
 +
 +  /* After dump, keep track of the "brk value" for sbrk(0).  */
 +  if (p)
 +    {
 +      unsigned char *new_brk = (unsigned char *)p + size;
 +
 +      if (new_brk > data_region_end)
 +      data_region_end = new_brk;
 +    }
 +  else
 +    errno = ENOMEM;
 +  return p;
 +}
  
 -  result = data_region_end;
 +void *
 +malloc_before_dump (size_t size)
 +{
 +  void *p;
  
 -  /* If size is negative, shrink the heap by decommitting pages.  */
 -  if (size < 0)
 +  /* Before dumping.  The private heap can handle only requests for
 +     less than MaxBlockSize.  */
 +  if (size < MaxBlockSize)
 +    {
 +      /* Use the private heap if possible.  */
 +      p = HeapAlloc (heap, 0, size);
 +      if (!p)
 +      errno = ENOMEM;
 +    }
 +  else
      {
 -      ptrdiff_t new_size;
 -      unsigned char *new_data_region_end;
 -
 -      size = -size;
 -
 -      /* Sanity checks.  */
 -      if ((data_region_end - size) < data_region_base)
 -      return NULL;
 -
 -      /* We can only decommit full pages, so allow for
 -       partial deallocation [cga].  */
 -      new_data_region_end = (data_region_end - size);
 -      new_data_region_end = (unsigned char *)
 -      ((DWORD_PTR) (new_data_region_end + syspage_mask) & ~syspage_mask);
 -      new_size = real_data_region_end - new_data_region_end;
 -      real_data_region_end = new_data_region_end;
 -      if (new_size > 0)
 +      /* Find the first big chunk that can hold the requested size.  */
 +      int i = 0;
 +
 +      for (i = 0; i < blocks_number; i++)
 +      {
 +        if (blocks[i].occupied == 0 && blocks[i].size >= size)
 +          break;
 +      }
 +      if (i < blocks_number)
 +      {
 +        /* If found, use it.  */
 +        p = blocks[i].address;
 +        blocks[i].occupied = TRUE;
 +      }
 +      else
        {
 -        /* Decommit size bytes from the end of the heap.  */
 -        if (using_dynamic_heap
 -            && !VirtualFree (real_data_region_end, new_size, MEM_DECOMMIT))
 -          return NULL;
 -      }
 +        /* Allocate a new big chunk from the end of the dumped_data
 +           array.  */
 +        if (blocks_number >= MAX_BLOCKS)
 +          {
 +            fprintf (stderr,
 +                     "malloc_before_dump: no more big chunks available.\nEnlarge MAX_BLOCKS!\n");
 +            exit (-1);
 +          }
 +        bc_limit -= size;
 +        bc_limit = (unsigned char *)ROUND_DOWN (bc_limit, 0x10);
 +        p = bc_limit;
 +        blocks[blocks_number].address = p;
 +        blocks[blocks_number].size = size;
 +        blocks[blocks_number].occupied = TRUE;
 +        blocks_number++;
 +        /* Check that areas do not overlap.  */
 +        if (bc_limit < dumped_data + committed)
 +          {
 +            fprintf (stderr,
 +                     "malloc_before_dump: memory exhausted.\nEnlarge dumped_data[]!\n");
 +            exit (-1);
 +          }
 +      }
 +    }
 +  return p;
 +}
  
 -      data_region_end -= size;
 +/* Re-allocate the previously allocated block in ptr, making the new
 +   block SIZE bytes long.  */
 +void *
 +realloc_after_dump (void *ptr, size_t size)
 +{
 +  void *p;
 +
 +  /* After dumping.  */
 +  if (FREEABLE_P (ptr))
 +    {
 +      /* Reallocate the block since it lies in the new heap.  */
 +      p = HeapReAlloc (heap, 0, ptr, size);
 +      if (!p)
 +      errno = ENOMEM;
      }
 -  /* If size is positive, grow the heap by committing reserved pages.  */
 -  else if (size > 0)
 +  else
      {
 -      /* Sanity checks.  */
 -      if ((data_region_end + size) >
 -        (data_region_base + get_reserved_heap_size ()))
 -      return NULL;
 -
 -      /* Commit more of our heap. */
 -      if (using_dynamic_heap
 -        && VirtualAlloc (data_region_end, size, MEM_COMMIT,
 -                         PAGE_READWRITE) == NULL)
 -      return NULL;
 -      data_region_end += size;
 -
 -      /* We really only commit full pages, so record where
 -       the real end of committed memory is [cga].  */
 -      real_data_region_end = (unsigned char *)
 -        ((DWORD_PTR) (data_region_end + syspage_mask) & ~syspage_mask);
 +      /* If the block lies in the dumped data, do not free it.  Only
 +         allocate a new one.  */
 +      p = HeapAlloc (heap, 0, size);
 +      if (p)
 +      CopyMemory (p, ptr, size);
 +      else
 +      errno = ENOMEM;
      }
 +  /* After dump, keep track of the "brk value" for sbrk(0).  */
 +  if (p)
 +    {
 +      unsigned char *new_brk = (unsigned char *)p + size;
  
 -  return result;
 +      if (new_brk > data_region_end)
 +      data_region_end = new_brk;
 +    }
 +  return p;
  }
  
 -/* Initialize the internal heap variables used by sbrk.  When running in
 -   preload phase (ie. in the undumped executable), we rely entirely on a
 -   fixed size heap section included in the .exe itself; this is
 -   preserved during dumping, and truncated to the size actually used.
 -
 -   When running in the dumped executable, we reserve as much as possible
 -   of the address range that is addressable by Lisp object pointers, to
 -   supplement what is left of the preload heap.  Although we cannot rely
 -   on the dynamically allocated arena being contiguous with the static
 -   heap area, it is not a problem because sbrk can pretend that the gap
 -   was allocated by something else; GNU malloc detects when there is a
 -   jump in the sbrk values, and starts a new heap block.  */
 -void
 -init_heap (void)
 +void *
 +realloc_before_dump (void *ptr, size_t size)
  {
 -  PIMAGE_DOS_HEADER dos_header;
 -  PIMAGE_NT_HEADERS nt_header;
 +  void *p;
  
 -  dos_header = (PIMAGE_DOS_HEADER) RVA_TO_PTR (0);
 -  nt_header = (PIMAGE_NT_HEADERS) (((DWORD_PTR) dos_header) +
 -                                 dos_header->e_lfanew);
 -  preload_heap_section = find_section ("EMHEAP", nt_header);
 -
 -  if (using_dynamic_heap)
 +  /* Before dumping.  */
 +  if (dumped_data < (unsigned char *)ptr
 +      && (unsigned char *)ptr < bc_limit && size <= MaxBlockSize)
      {
 -      data_region_base = allocate_heap ();
 -      if (!data_region_base)
 +      p = HeapReAlloc (heap, 0, ptr, size);
 +      if (!p)
 +      errno = ENOMEM;
 +    }
 +  else
 +    {
 +      /* In this case, either the new block is too large for the heap,
 +         or the old block was already too large.  In both cases,
 +         malloc_before_dump() and free_before_dump() will take care of
 +         reallocation.  */
 +      p = malloc_before_dump (size);
 +      /* If SIZE is below MaxBlockSize, malloc_before_dump will try to
 +       allocate it in the fixed heap.  If that fails, we could have
 +       kept the block in its original place, above bc_limit, instead
 +       of failing the call as below.  But this doesn't seem to be
 +       worth the added complexity, as loadup allocates only a very
 +       small number of large blocks, and never reallocates them.  */
 +      if (p)
        {
 -        printf ("Error: Could not reserve dynamic heap area.\n");
 -        exit (1);
 +        CopyMemory (p, ptr, size);
 +        free_before_dump (ptr);
        }
 +    }
 +  return p;
 +}
 +
 +/* Free a block allocated by `malloc', `realloc' or `calloc'.  */
 +void
 +free_after_dump (void *ptr)
 +{
 +  /* After dumping.  */
 +  if (FREEABLE_P (ptr))
 +    {
 +      /* Free the block if it is in the new private heap.  */
 +      HeapFree (heap, 0, ptr);
 +    }
 +}
 +
 +void
 +free_before_dump (void *ptr)
 +{
 +  /* Before dumping.  */
 +  if (dumped_data < (unsigned char *)ptr
 +      && (unsigned char *)ptr < bc_limit)
 +    {
 +      /* Free the block if it is allocated in the private heap.  */
 +      HeapFree (heap, 0, ptr);
 +    }
 +  else
 +    {
 +      /* Look for the big chunk.  */
 +      int i;
  
 -#if !USE_LSB_TAG
 -      /* Ensure that the addresses don't use the upper tag bits since
 -       the Lisp type goes there.  */
 -      if (((DWORD_PTR) data_region_base & ~VALMASK) != 0)
 +      for (i = 0; i < blocks_number; i++)
        {
 -        printf ("Error: The heap was allocated in upper memory.\n");
 -        exit (1);
 +        if (blocks[i].address == ptr)
 +          {
 +            /* Reset block occupation if found.  */
 +            blocks[i].occupied = 0;
 +            break;
 +          }
 +        /* What if the block is not found?  We should trigger an
 +           error here.  */
 +        eassert (i < blocks_number);
        }
 +    }
 +}
 +
 +#ifdef ENABLE_CHECKING
 +void
 +report_temacs_memory_usage (void)
 +{
 +  DWORD blocks_used = 0;
 +  size_t large_mem_used = 0;
 +  int i;
 +
 +  for (i = 0; i < blocks_number; i++)
 +    if (blocks[i].occupied)
 +      {
 +      blocks_used++;
 +      large_mem_used += blocks[i].size;
 +      }
 +
 +  /* Emulate 'message', which writes to stderr in non-interactive
 +     sessions.  */
 +  fprintf (stderr,
 +         "Dump memory usage: Heap: %" PRIu64 "  Large blocks(%lu/%lu): %" PRIu64 "/%" PRIu64 "\n",
 +         (unsigned long long)committed, blocks_used, blocks_number,
 +         (unsigned long long)large_mem_used,
 +         (unsigned long long)(dumped_data + DUMPED_HEAP_SIZE - bc_limit));
 +}
  #endif
 -      data_region_end = data_region_base;
 -      real_data_region_end = data_region_end;
 +
 +/* Emulate getpagesize. */
 +int
 +getpagesize (void)
 +{
 +  return sysinfo_cache.dwPageSize;
 +}
 +
 +void *
 +sbrk (ptrdiff_t increment)
 +{
 +  /* data_region_end is the address beyond the last allocated byte.
 +     The sbrk() function is not emulated at all, except for a 0 value
 +     of its parameter.  This is needed by the Emacs Lisp function
 +     `memory-limit'.  */
 +  eassert (increment == 0);
 +  return data_region_end;
 +}
 +
 +#define MAX_BUFFER_SIZE (512 * 1024 * 1024)
 +
 +/* MMAP allocation for buffers.  */
 +void *
 +mmap_alloc (void **var, size_t nbytes)
 +{
 +  void *p = NULL;
 +
 +  /* We implement amortized allocation.  We start by reserving twice
 +     the size requested and commit only the size requested.  Then
 +     realloc could proceed and use the reserved pages, reallocating
 +     only if needed.  Buffer shrink would happen only so that we stay
 +     in the 2x range.  This is a big win when visiting compressed
 +     files, where the final size of the buffer is not known in
 +     advance, and the buffer is enlarged several times as the data is
 +     decompressed on the fly.  */
 +  if (nbytes < MAX_BUFFER_SIZE)
 +    p = VirtualAlloc (NULL, (nbytes * 2), MEM_RESERVE, PAGE_READWRITE);
 +
 +  /* If it fails, or if the request is above 512MB, try with the
 +     requested size.  */
 +  if (p == NULL)
 +    p = VirtualAlloc (NULL, nbytes, MEM_RESERVE, PAGE_READWRITE);
 +
 +  if (p != NULL)
 +    {
 +      /* Now, commit pages for NBYTES.  */
 +      *var = VirtualAlloc (p, nbytes, MEM_COMMIT, PAGE_READWRITE);
      }
 -  else
 +
 +  if (!p)
      {
 -      data_region_base = RVA_TO_PTR (preload_heap_section->VirtualAddress);
 -      data_region_end = data_region_base;
 -      real_data_region_end = data_region_end;
 -      reserved_heap_size = preload_heap_section->Misc.VirtualSize;
 +      if (GetLastError () == ERROR_NOT_ENOUGH_MEMORY)
 +      errno = ENOMEM;
 +      else
 +      {
 +        DebPrint (("mmap_alloc: error %ld\n", GetLastError ()));
 +        errno = EINVAL;
 +      }
      }
  
 -  /* Update system version information to match current system.  */
 -  cache_system_info ();
 +  return *var = p;
  }
  
 -/* Round the heap up to the given alignment.  */
  void
 -round_heap (size_t align)
 +mmap_free (void **var)
  {
 -  DWORD_PTR needs_to_be;
 -  DWORD_PTR need_to_alloc;
 +  if (*var)
 +    {
 +      if (VirtualFree (*var, 0, MEM_RELEASE) == 0)
 +        DebPrint (("mmap_free: error %ld\n", GetLastError ()));
 +      *var = NULL;
 +    }
 +}
 +
 +void *
 +mmap_realloc (void **var, size_t nbytes)
 +{
 +  MEMORY_BASIC_INFORMATION memInfo, m2;
 +
 +  if (*var == NULL)
 +    return mmap_alloc (var, nbytes);
 +
 +  /* This case happens in init_buffer().  */
 +  if (nbytes == 0)
 +    {
 +      mmap_free (var);
 +      return mmap_alloc (var, nbytes);
 +    }
 +
 +  if (VirtualQuery (*var, &memInfo, sizeof (memInfo)) == 0)
 +    DebPrint (("mmap_realloc: VirtualQuery error = %ld\n", GetLastError ()));
  
 -  needs_to_be = (DWORD_PTR) ROUND_UP (get_heap_end (), align);
 -  need_to_alloc = needs_to_be - (DWORD_PTR) get_heap_end ();
 +  /* We need to enlarge the block.  */
 +  if (memInfo.RegionSize < nbytes)
 +    {
 +      if (VirtualQuery (*var + memInfo.RegionSize, &m2, sizeof(m2)) == 0)
 +        DebPrint (("mmap_realloc: VirtualQuery error = %ld\n",
 +                 GetLastError ()));
 +      /* If there is enough room in the current reserved area, then
 +       commit more pages as needed.  */
 +      if (m2.State == MEM_RESERVE
 +        && nbytes <= memInfo.RegionSize + m2.RegionSize)
 +      {
 +        void *p;
 +
 +        p = VirtualAlloc (*var + memInfo.RegionSize,
 +                          nbytes - memInfo.RegionSize,
 +                          MEM_COMMIT, PAGE_READWRITE);
 +        if (!p /* && GetLastError() != ERROR_NOT_ENOUGH_MEMORY */)
 +          {
 +            DebPrint (("realloc enlarge: VirtualAlloc error %ld\n",
 +                       GetLastError ()));
 +            errno = ENOMEM;
 +          }
 +        return *var;
 +      }
 +      else
 +      {
 +        /* Else we must actually enlarge the block by allocating a
 +           new one and copying previous contents from the old to the
 +           new one.  */
 +        void *old_ptr = *var;
 +
 +        if (mmap_alloc (var, nbytes))
 +          {
 +            CopyMemory (*var, old_ptr, memInfo.RegionSize);
 +            mmap_free (&old_ptr);
 +            return *var;
 +          }
 +        else
 +          {
 +            /* We failed to enlarge the buffer.  */
 +            *var = old_ptr;
 +            return NULL;
 +          }
 +      }
 +    }
 +
 +  /* If we are shrinking by more than one page...  */
 +  if (memInfo.RegionSize  > nbytes + getpagesize())
 +    {
 +      /* If we are shrinking a lot...  */
 +      if ((memInfo.RegionSize / 2) > nbytes)
 +        {
 +          /* Let's give some memory back to the system and release
 +           some pages.  */
 +          void *old_ptr = *var;
 +
 +        if (mmap_alloc (var, nbytes))
 +            {
 +              CopyMemory (*var, old_ptr, nbytes);
 +              mmap_free (&old_ptr);
 +              return *var;
 +            }
 +          else
 +          {
 +            /* In case we fail to shrink, try to go on with the old block.
 +               But that means there is a lot of memory pressure.
 +               We could also decommit pages.  */
 +            *var = old_ptr;
 +            return *var;
 +          }
 +        }
 +
 +      /* We still can decommit pages.  */
 +      if (VirtualFree (*var + nbytes + get_page_size(),
 +                     memInfo.RegionSize - nbytes - get_page_size(),
 +                     MEM_DECOMMIT) == 0)
 +        DebPrint (("mmap_realloc: VirtualFree error %ld\n", GetLastError ()));
 +      return *var;
 +    }
  
 -  if (need_to_alloc)
 -    sbrk (need_to_alloc);
 +  /* Not enlarging, not shrinking by more than one page.  */
 +  return *var;
  }