+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, ROUND_UP (nbytes * 2, get_allocation_unit ()),
+ 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, ROUND_UP (nbytes, get_allocation_unit ()),
+ MEM_RESERVE, PAGE_READWRITE);
+
+ if (p != NULL)
+ {
+ /* Now, commit pages for NBYTES. */
+ *var = VirtualAlloc (p, nbytes, MEM_COMMIT, PAGE_READWRITE);
+ if (*var == NULL)
+ p = *var;
+ }
+
+ if (!p)
+ {
+ DWORD e = GetLastError ();
+
+ if (e == ERROR_NOT_ENOUGH_MEMORY)
+ errno = ENOMEM;
+ else
+ {
+ DebPrint (("mmap_alloc: error %ld\n", e));
+ errno = EINVAL;
+ }
+ }
+
+ return *var = p;
+}
+
+void
+mmap_free (void **var)
+{
+ if (*var)
+ {
+ if (VirtualFree (*var, 0, MEM_RELEASE) == 0)
+ DebPrint (("mmap_free: error %ld\n", GetLastError ()));
+ *var = NULL;
+ }
+}
+
+void *
+mmap_realloc (void **var, size_t nbytes)
+{
+ MEMORY_BASIC_INFORMATION memInfo, m2;
+ void *old_ptr;
+
+ 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);
+ }
+
+ memset (&memInfo, 0, sizeof (memInfo));
+ if (VirtualQuery (*var, &memInfo, sizeof (memInfo)) == 0)
+ DebPrint (("mmap_realloc: VirtualQuery error = %ld\n", GetLastError ()));
+
+ /* We need to enlarge the block. */
+ if (memInfo.RegionSize < nbytes)
+ {
+ memset (&m2, 0, sizeof (m2));
+ if (VirtualQuery ((char *)*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
+ && m2.AllocationBase == memInfo.AllocationBase
+ && nbytes <= memInfo.RegionSize + m2.RegionSize)
+ {
+ void *p;
+
+ p = VirtualAlloc (*var, nbytes, MEM_COMMIT, PAGE_READWRITE);
+ if (!p /* && GetLastError() != ERROR_NOT_ENOUGH_MEMORY */)
+ {
+ DebPrint (("realloc enlarge: VirtualAlloc (%p + %I64x, %I64x) error %ld\n",
+ *var, (uint64_t)memInfo.RegionSize,
+ (uint64_t)(nbytes - memInfo.RegionSize),
+ GetLastError ()));
+ DebPrint (("next region: %p %p %I64x %x\n", m2.BaseAddress,
+ m2.AllocationBase, (uint64_t)m2.RegionSize,
+ m2.AllocationProtect));
+ }
+ else
+ return *var;
+ }
+ /* Else we must actually enlarge the block by allocating a new
+ one and copying previous contents from the old to the new one. */
+ old_ptr = *var;
+
+ if (mmap_alloc (var, nbytes))
+ {
+ CopyMemory (*var, old_ptr, memInfo.RegionSize);
+ mmap_free (&old_ptr);
+ return *var;
+ }
+ else
+ {
+ /* We failed to reallocate 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. */
+ 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 ((char *)*var + nbytes + get_page_size(),
+ memInfo.RegionSize - nbytes - get_page_size(),
+ MEM_DECOMMIT) == 0)
+ DebPrint (("mmap_realloc: VirtualFree error %ld\n", GetLastError ()));
+ return *var;
+ }