-/* 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-2016 Free Software Foundation, Inc.
This file is part of GNU Emacs.
#include <sys/mman.h>
#include "w32common.h"
#include "w32heap.h"
-#include "lisp.h" /* for VALMASK */
+#include "lisp.h"
/* We chose to leave those declarations here. They are used only in
this file. The RtlCreateHeap is available since XP. It is located
typedef LONG NTSTATUS;
-typedef NTSTATUS
-(NTAPI * PRTL_HEAP_COMMIT_ROUTINE)(
- IN PVOID Base,
- IN OUT PVOID *CommitAddress,
- IN OUT PSIZE_T CommitSize
- );
+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;
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
+ available inside the NT kernel since XP will do this. It allows the
+ creation of 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
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)
+# define DUMPED_HEAP_SIZE (20*1024*1024)
#else
-# define DUMPED_HEAP_SIZE (11*1024*1024)
+# define DUMPED_HEAP_SIZE (12*1024*1024)
#endif
static unsigned char dumped_data[DUMPED_HEAP_SIZE];
}
#endif
- the_malloc_fn = malloc_after_dump;
- the_realloc_fn = realloc_after_dump;
- the_free_fn = free_after_dump;
+ if (os_subtype == OS_9X)
+ {
+ the_malloc_fn = malloc_after_dump_9x;
+ the_realloc_fn = realloc_after_dump_9x;
+ the_free_fn = free_after_dump_9x;
+ }
+ else
+ {
+ the_malloc_fn = malloc_after_dump;
+ the_realloc_fn = realloc_after_dump;
+ the_free_fn = free_after_dump;
+ }
}
else
{
exit (-1);
}
heap = s_pfn_Rtl_Create_Heap (0, data_region_base, 0, 0, NULL, ¶ms);
- the_malloc_fn = malloc_before_dump;
- the_realloc_fn = realloc_before_dump;
- the_free_fn = free_before_dump;
+
+ if (os_subtype == OS_9X)
+ {
+ fprintf (stderr, "Cannot dump Emacs on Windows 9X; exiting.\n");
+ exit (-1);
+ }
+ else
+ {
+ the_malloc_fn = malloc_before_dump;
+ the_realloc_fn = realloc_before_dump;
+ the_free_fn = free_before_dump;
+ }
}
/* Update system version information to match current system. */
#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)
+#define FREEABLE_P(addr) \
+ ((unsigned char *)(addr) > 0 \
+ && ((unsigned char *)(addr) < dumped_data \
+ || (unsigned char *)(addr) >= dumped_data + DUMPED_HEAP_SIZE))
void *
malloc_after_dump (size_t size)
/* 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
+ if (!p)
errno = ENOMEM;
+ else if (ptr)
+ CopyMemory (p, ptr, size);
}
/* After dump, keep track of the "brk value" for sbrk(0). */
if (p)
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)
+ if (p && ptr)
{
CopyMemory (p, ptr, size);
free_before_dump (ptr);
void
free_before_dump (void *ptr)
{
+ if (!ptr)
+ return;
+
/* Before dumping. */
if (dumped_data < (unsigned char *)ptr
&& (unsigned char *)ptr < bc_limit)
}
}
+/* On Windows 9X, HeapAlloc may return pointers that are not aligned
+ on 8-byte boundary, alignment which is required by the Lisp memory
+ management. To circumvent this problem, manually enforce alignment
+ on Windows 9X. */
+
+void *
+malloc_after_dump_9x (size_t size)
+{
+ void *p = malloc_after_dump (size + 8);
+ void *pa;
+ if (p == NULL)
+ return p;
+ pa = (void*)(((intptr_t)p + 8) & ~7);
+ *((void**)pa-1) = p;
+ return pa;
+}
+
+void *
+realloc_after_dump_9x (void *ptr, size_t size)
+{
+ if (FREEABLE_P (ptr))
+ {
+ void *po = *((void**)ptr-1);
+ void *p;
+ void *pa;
+ p = realloc_after_dump (po, size + 8);
+ if (p == NULL)
+ return p;
+ pa = (void*)(((intptr_t)p + 8) & ~7);
+ if (ptr != NULL &&
+ (char*)pa - (char*)p != (char*)ptr - (char*)po)
+ {
+ /* Handle the case where alignment in pre-realloc and
+ post-realloc blocks does not match. */
+ MoveMemory (pa, (void*)((char*)p + ((char*)ptr - (char*)po)), size);
+ }
+ *((void**)pa-1) = p;
+ return pa;
+ }
+ else
+ {
+ /* Non-freeable pointers have no alignment-enforcing header
+ (since dumping is not allowed on Windows 9X). */
+ void* p = malloc_after_dump_9x (size);
+ if (p != NULL)
+ CopyMemory (p, ptr, size);
+ return p;
+ }
+}
+
+void
+free_after_dump_9x (void *ptr)
+{
+ if (FREEABLE_P (ptr))
+ {
+ free_after_dump (*((void**)ptr-1));
+ }
+}
+
#ifdef ENABLE_CHECKING
void
report_temacs_memory_usage (void)
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);
+ 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, nbytes, MEM_RESERVE, PAGE_READWRITE);
+ 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)
{
- if (GetLastError () == ERROR_NOT_ENOUGH_MEMORY)
+ DWORD e = GetLastError ();
+
+ if (e == ERROR_NOT_ENOUGH_MEMORY)
errno = ENOMEM;
else
{
- DebPrint (("mmap_alloc: error %ld\n", GetLastError ()));
+ DebPrint (("mmap_alloc: error %ld\n", e));
errno = EINVAL;
}
}
mmap_realloc (void **var, size_t nbytes)
{
MEMORY_BASIC_INFORMATION memInfo, m2;
+ void *old_ptr;
if (*var == NULL)
return mmap_alloc (var, nbytes);
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 (*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 + memInfo.RegionSize,
- nbytes - memInfo.RegionSize,
- MEM_COMMIT, PAGE_READWRITE);
+ p = VirtualAlloc (*var, nbytes, MEM_COMMIT, PAGE_READWRITE);
if (!p /* && GetLastError() != ERROR_NOT_ENOUGH_MEMORY */)
{
- DebPrint (("realloc enlarge: VirtualAlloc error %ld\n",
+ DebPrint (("realloc enlarge: VirtualAlloc (%p + %I64x, %I64x) error %ld\n",
+ *var, (uint64_t)memInfo.RegionSize,
+ (uint64_t)(nbytes - memInfo.RegionSize),
GetLastError ()));
- errno = ENOMEM;
+ 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
{
- /* 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;
- }
+ /* We failed to reallocate the buffer. */
+ *var = old_ptr;
+ return NULL;
}
}
{
/* Let's give some memory back to the system and release
some pages. */
- void *old_ptr = *var;
+ old_ptr = *var;
if (mmap_alloc (var, nbytes))
{