guile-elisp bootstrap part (C)
[bpt/emacs.git] / src / w32heap.c
index 523df90..c431b87 100644 (file)
@@ -108,11 +108,21 @@ typedef struct _RTL_HEAP_PARAMETERS {
    be freed anyway), and we use a new private heap for all new
    allocations.  */
 
-unsigned char dumped_data[DUMPED_HEAP_SIZE];
+/* 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.  */
+#ifdef _WIN64
+# 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. */
-/* Info for keeping track of our heap. */
+static unsigned char dumped_data[DUMPED_HEAP_SIZE];
+
+/* Info for keeping track of our dynamic heap used after dumping. */
 unsigned char *data_region_base = NULL;
 unsigned char *data_region_end = NULL;
 static DWORD_PTR committed = 0;
@@ -143,7 +153,9 @@ static DWORD_PTR committed = 0;
                   + committed
 
 */
-#define HEAP_ENTRY_SHIFT 3
+
+/* 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)
 
@@ -188,12 +200,11 @@ dumped_data_commit (PVOID Base, PVOID *CommitAddress, PSIZE_T CommitSize)
      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)
     {
-      /* Check that the private heap area does not overlap the big
-        chunks area.  */
-      fprintf(stderr,
-             "dumped_data_commit: memory exhausted.\nEnlarge dumped_data[]!\n");
+      fprintf (stderr,
+              "dumped_data_commit: memory exhausted.\nEnlarge dumped_data[]!\n");
       exit (-1);
     }
   return 0;
@@ -201,7 +212,7 @@ dumped_data_commit (PVOID Base, PVOID *CommitAddress, PSIZE_T CommitSize)
 
 /* Heap creation.  */
 
-/* Under MinGW32, we want to turn on Low Fragmentation Heap for XP.
+/* We want to turn on Low Fragmentation Heap for XP and older systems.
    MinGW32 lacks those definitions.  */
 #ifndef _W64
 typedef enum _HEAP_INFORMATION_CLASS {
@@ -219,9 +230,9 @@ init_heap (void)
       unsigned long enable_lfh = 2;
 
       /* After dumping, use a new private heap.  We explicitly enable
-         the low fragmentation heap here, for the sake of pre Vista
-         versions.  Note: this will harnlessly fail on Vista and
-         later, whyere the low fragmentation heap is enabled by
+         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
@@ -231,19 +242,20 @@ init_heap (void)
       data_region_end = data_region_base;
 
       /* Create the private heap.  */
-      heap = HeapCreate(0, 0, 0);
+      heap = HeapCreate (0, 0, 0);
 
 #ifndef _W64
-      /* Set the low-fragmentation heap for OS before XP and Windows
-        Server 2003.  */
-      HMODULE hm_kernel32dll = LoadLibrary("kernel32.dll");
-      HeapSetInformation_Proc s_pfn_Heap_Set_Information = (HeapSetInformation_Proc) GetProcAddress(hm_kernel32dll, "HeapSetInformation");
+      /* 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 ()));
+       {
+         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
 
       the_malloc_fn = malloc_after_dump;
@@ -260,7 +272,7 @@ init_heap (void)
        = (RtlCreateHeap_Proc) GetProcAddress (hm_ntdll, "RtlCreateHeap");
       /* Specific parameters for the private heap.  */
       RTL_HEAP_PARAMETERS params;
-      ZeroMemory(&params, sizeof(params));
+      ZeroMemory (&params, sizeof(params));
       params.Length = sizeof(RTL_HEAP_PARAMETERS);
 
       data_region_base = (unsigned char *)ROUND_UP (dumped_data, 0x1000);
@@ -273,6 +285,11 @@ init_heap (void)
       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;
@@ -285,7 +302,6 @@ init_heap (void)
 
 #undef malloc
 #undef realloc
-#undef calloc
 #undef free
 
 /* FREEABLE_P checks if the block can be safely freed.  */
@@ -299,9 +315,14 @@ malloc_after_dump (size_t size)
   /* Use the new private heap.  */
   void *p = HeapAlloc (heap, 0, size);
 
-  /* After dump, keep track of the last allocated byte for sbrk(0).  */
+  /* After dump, keep track of the "brk value" for sbrk(0).  */
   if (p)
-    data_region_end = p + size - 1;
+    {
+      unsigned char *new_brk = (unsigned char *)p + size;
+
+      if (new_brk > data_region_end)
+       data_region_end = new_brk;
+    }
   else
     errno = ENOMEM;
   return p;
@@ -343,8 +364,8 @@ malloc_before_dump (size_t size)
             array.  */
          if (blocks_number >= MAX_BLOCKS)
            {
-             fprintf(stderr,
-                     "malloc_before_dump: no more big chunks available.\nEnlarge MAX_BLOCKS!\n");
+             fprintf (stderr,
+                      "malloc_before_dump: no more big chunks available.\nEnlarge MAX_BLOCKS!\n");
              exit (-1);
            }
          bc_limit -= size;
@@ -354,11 +375,11 @@ malloc_before_dump (size_t size)
          blocks[blocks_number].size = size;
          blocks[blocks_number].occupied = TRUE;
          blocks_number++;
+         /* Check that areas do not overlap.  */
          if (bc_limit < dumped_data + committed)
            {
-             /* Check that areas do not overlap.  */
-             fprintf(stderr,
-                     "malloc_before_dump: memory exhausted.\nEnlarge dumped_data[]!\n");
+             fprintf (stderr,
+                      "malloc_before_dump: memory exhausted.\nEnlarge dumped_data[]!\n");
              exit (-1);
            }
        }
@@ -391,9 +412,14 @@ realloc_after_dump (void *ptr, size_t size)
       else
        errno = ENOMEM;
     }
-  /* After dump, keep track of the last allocated byte for sbrk(0).  */
+  /* After dump, keep track of the "brk value" for sbrk(0).  */
   if (p)
-    data_region_end = p + size - 1;
+    {
+      unsigned char *new_brk = (unsigned char *)p + size;
+
+      if (new_brk > data_region_end)
+       data_region_end = new_brk;
+    }
   return p;
 }
 
@@ -459,7 +485,7 @@ free_before_dump (void *ptr)
       /* Look for the big chunk.  */
       int i;
 
-      for(i = 0; i < blocks_number; i++)
+      for (i = 0; i < blocks_number; i++)
        {
          if (blocks[i].address == ptr)
            {
@@ -478,11 +504,23 @@ free_before_dump (void *ptr)
 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): %" PRIu64 "\n",
-          (unsigned long long)committed, blocks_number,
+          "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
@@ -497,10 +535,11 @@ getpagesize (void)
 void *
 sbrk (ptrdiff_t increment)
 {
-  /* The data_region_end address is the one of the last byte
-     allocated.  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'.   */
+  /* 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;
 }