2720
|
1 /* New size-based allocator for XEmacs.
|
|
2 Copyright (C) 2005 Marcus Crestani.
|
|
3
|
|
4 This file is part of XEmacs.
|
|
5
|
|
6 XEmacs is free software; you can redistribute it and/or modify it
|
|
7 under the terms of the GNU General Public License as published by the
|
|
8 Free Software Foundation; either version 2, or (at your option) any
|
|
9 later version.
|
|
10
|
|
11 XEmacs is distributed in the hope that it will be useful, but WITHOUT
|
|
12 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
13 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
|
14 for more details.
|
|
15
|
|
16 You should have received a copy of the GNU General Public License
|
|
17 along with XEmacs; see the file COPYING. If not, write to
|
|
18 the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
|
|
19 Boston, MA 02111-1307, USA. */
|
|
20
|
|
21 /* Synched up with: Not in FSF. */
|
|
22
|
|
23 #include <config.h>
|
|
24 #include "lisp.h"
|
|
25 #include "mc-alloc.h"
|
|
26
|
|
27
|
|
28 /*--- configurable values ----------------------------------------------*/
|
|
29
|
|
30 /* Valid page sizes are powers of 2. */
|
|
31 #undef PAGE_SIZE /* for FreeBSD */
|
|
32 #define PAGE_SIZE 2048
|
|
33
|
|
34
|
|
35 /* Definition of size classes */
|
|
36
|
|
37 /* Heap used list constants: In the used heap, it is important to
|
|
38 quickly find a free spot for a new object. Therefore the size
|
|
39 classes of the used heap are defined by the size of the cells on
|
|
40 the pages. The size classes should match common object sizes, to
|
|
41 avoid wasting memory. */
|
|
42
|
|
43 /* Minimum object size in bytes. */
|
|
44 #define USED_LIST_MIN_OBJECT_SIZE 8
|
|
45
|
|
46 /* The step size by which the size classes increase (up to upper
|
|
47 threshold). This many bytes are mapped to a single used list: */
|
|
48 #define USED_LIST_LIN_STEP 4
|
|
49
|
|
50 /* The upper threshold should always be set to PAGE_SIZE/2, because if
|
|
51 a object is larger than PAGE_SIZE/2 there is no room for any other
|
|
52 object on this page. Objects this big are kept in the page list of
|
|
53 the multiple pages, since a quick search for free spots is not
|
|
54 needed for this kind of pages (because there are no free spots).
|
|
55 PAGE_SIZES_DIV_2 defines maximum size of a used space list. */
|
|
56 #define USED_LIST_UPPER_THRESHOLD PAGE_SIZE_DIV_2
|
|
57
|
|
58
|
|
59 /* Unmanaged memory used list constants: Like in the used heap, it is
|
|
60 important to quickly find a free spot for a new object. Therefore
|
|
61 the size classes of the unmanaged heap are defined by the size of
|
|
62 the cells on the pages. The size classes should match common object
|
|
63 sizes, to avoid wasting memory. */
|
|
64 /* Minimum object size in bytes. */
|
|
65 #define UNMANAGED_LIST_MIN_OBJECT_SIZE 8
|
|
66 /* The step size by which the size classes increase (up to upper
|
|
67 threshold). This many bytes are mapped to a single unmanaged list: */
|
|
68 #define UNMANAGED_LIST_LIN_STEP 4
|
|
69 /* The upper threshold should always be set to PAGE_SIZE/2, because if
|
|
70 a object is larger than PAGE_SIZE/2 there is no room for any other
|
|
71 object on this page. Objects this big are kept in the page list of
|
|
72 the multiple pages, since a quick search for free spots is not
|
|
73 needed for this kind of pages (because there are no free spots).
|
|
74 PAGE_SIZES defines maximum size of a unmanaged space list. */
|
|
75 #define UNMANAGED_LIST_UPPER_THRESHOLD PAGE_SIZE_DIV_2
|
|
76
|
|
77
|
|
78 /* Heap free list constants: In the unused heap, the size of
|
|
79 consecutive memory tips the scales. A page is smallest entity which
|
|
80 is asked for. Therefore, the size classes of the unused heap are
|
|
81 defined by the number of consecutive pages. */
|
|
82 /* Sizes up to this many pages each have their own free list. */
|
|
83 #define FREE_LIST_LOWER_THRESHOLD 32
|
|
84 /* The step size by which the size classes increase (up to upper
|
|
85 threshold). FREE_LIST_LIN_STEP number of sizes are mapped to a
|
|
86 single free list for sizes between FREE_LIST_LOWER_THRESHOLD and
|
|
87 FREE_LIST_UPPER_THRESHOLD. */
|
|
88 #define FREE_LIST_LIN_STEP 8
|
|
89 /* Sizes of at least this many pages are mapped to a single free
|
|
90 list. Blocks of memory larger than this number are all kept in a
|
|
91 single list, which makes searching this list slow. But objects that
|
|
92 big are really seldom. */
|
|
93 #define FREE_LIST_UPPER_THRESHOLD 256
|
|
94
|
|
95
|
|
96 /* Maximum number of separately added heap sections. */
|
|
97 #if BITS_PER_EMACS_INT > 32
|
|
98 # define MAX_HEAP_SECTS 2048
|
|
99 #else
|
|
100 # define MAX_HEAP_SECTS 768
|
|
101 #endif
|
|
102
|
|
103
|
|
104 /* Heap growth constants. Heap increases by any number between the
|
|
105 boundaries (unit is PAGE_SIZE). */
|
|
106 #define MIN_HEAP_INCREASE 32
|
|
107 #define MAX_HEAP_INCREASE 256 /* not used */
|
|
108
|
|
109 /* Every heap growth is calculated like this:
|
|
110 needed_pages + ( HEAP_SIZE / ( PAGE_SIZE * HEAP_GROWTH_DIVISOR )).
|
|
111 So the growth of the heap is influenced by the current size of the
|
|
112 heap, but kept between MIN_HEAP_INCREASE and MAX_HEAP_INCREASE
|
|
113 boundaries.
|
|
114 This reduces the number of heap sectors, the larger the heap grows
|
|
115 the larger are the newly allocated chunks. */
|
|
116 #define HEAP_GROWTH_DIVISOR 3
|
|
117
|
|
118
|
|
119 /* Zero memory before putting on free lists. */
|
|
120 #define ZERO_MEM 1
|
|
121
|
|
122
|
|
123
|
|
124
|
|
125 /*--- calculations done by macros --------------------------------------*/
|
|
126
|
|
127 #ifndef CHAR_BIT /* should be included by limits.h */
|
|
128 # define CHAR_BIT BITS_PER_CHAR
|
|
129 #endif
|
|
130
|
|
131 #if PAGE_SIZE == 512
|
|
132 # define CPP_LOG_PAGE_SIZE 9
|
|
133 #endif
|
|
134 #if PAGE_SIZE == 1024
|
|
135 # define CPP_LOG_PAGE_SIZE 10
|
|
136 #endif
|
|
137 #if PAGE_SIZE == 2048
|
|
138 # define CPP_LOG_PAGE_SIZE 11
|
|
139 #endif
|
|
140 #if PAGE_SIZE == 4096
|
|
141 # define CPP_LOG_PAGE_SIZE 12
|
|
142 #endif
|
|
143 #if PAGE_SIZE == 8192
|
|
144 # define CPP_LOG_PAGE_SIZE 13
|
|
145 #endif
|
|
146 #if PAGE_SIZE == 16384
|
|
147 # define CPP_LOG_PAGE_SIZE 14
|
|
148 #endif
|
|
149 #ifndef CPP_LOG_PAGE_SIZE
|
|
150 --> fix PAGE_SIZE
|
|
151 #endif
|
|
152 #undef PAGE_SIZE
|
|
153 #define CPP_PAGE_SIZE (1 << CPP_LOG_PAGE_SIZE)
|
|
154 #define LOG_PAGE_SIZE ((EMACS_INT) CPP_LOG_PAGE_SIZE)
|
|
155 #define PAGE_SIZE ((EMACS_INT) CPP_PAGE_SIZE)
|
|
156 #define PAGE_SIZE_DIV_2 (PAGE_SIZE >> 1)
|
|
157
|
|
158
|
|
159 /* NOT USED ANYMORE */
|
|
160 #ifdef USE_EXPONENTIAL_USED_LIST_GROWTH
|
|
161 /* used heap list logarithms */
|
|
162 #if USED_LIST_LOWER_THRESHOLD == 8
|
|
163 # define CPP_LOG_USED_LIST_LOWER_THRESHOLD 3
|
|
164 #endif
|
|
165 #if USED_LIST_LOWER_THRESHOLD == 16
|
|
166 # define CPP_LOG_USED_LIST_LOWER_THRESHOLD 4
|
|
167 #endif
|
|
168 #if USED_LIST_LOWER_THRESHOLD == 32
|
|
169 # define CPP_LOG_USED_LIST_LOWER_THRESHOLD 5
|
|
170 #endif
|
|
171 #if USED_LIST_LOWER_THRESHOLD == 64
|
|
172 # define CPP_LOG_USED_LIST_LOWER_THRESHOLD 6
|
|
173 #endif
|
|
174 #if USED_LIST_LOWER_THRESHOLD == 128
|
|
175 # define CPP_LOG_USED_LIST_LOWER_THRESHOLD 7
|
|
176 #endif
|
|
177 #if USED_LIST_LOWER_THRESHOLD == 256
|
|
178 # define CPP_LOG_USED_LIST_LOWER_THRESHOLD 8
|
|
179 #endif
|
|
180 #ifndef CPP_LOG_USED_LIST_LOWER_THRESHOLD
|
|
181 --> fix USED_LIST_LOWER_THRESHOLD
|
|
182 #endif
|
|
183 #define LOG_USED_LIST_LOWER_THRESHOLD CPP_LOG_USED_LIST_LOWER_THRESHOLD
|
|
184 #endif /* USE_EXPONENTIAL_USED_LIST_GROWTH */
|
|
185
|
|
186 /* used heap list count */
|
|
187 #define N_USED_PAGE_LISTS (((USED_LIST_UPPER_THRESHOLD \
|
|
188 - USED_LIST_MIN_OBJECT_SIZE) \
|
|
189 / USED_LIST_LIN_STEP) + 1 ) + 1
|
|
190
|
|
191 /* unmanaged memory list count */
|
|
192 #define N_UNMANAGED_PAGE_LISTS (((UNMANAGED_LIST_UPPER_THRESHOLD \
|
|
193 - UNMANAGED_LIST_MIN_OBJECT_SIZE) \
|
|
194 / UNMANAGED_LIST_LIN_STEP) + 1 ) + 1
|
|
195
|
|
196 /* NOT USED ANYMORE */
|
|
197 #ifdef USE_EXPONENTIAL_USED_LIST_GROWTH
|
|
198 #define N_USED_PAGE_LISTS_LIN (((USED_LIST_LOWER_THRESHOLD \
|
|
199 - USED_LIST_MIN_OBJECT_SIZE) \
|
|
200 / USED_LIST_LIN_STEP) + 1 )
|
|
201 #define N_USED_PAGE_LISTS_EXP \
|
|
202 (LOG_PAGE_SIZE - LOG_USED_LIST_LOWER_THRESHOLD)
|
|
203
|
|
204 #define N_USED_PAGE_LISTS \
|
|
205 (N_USED_PAGE_LISTS_LIN + N_USED_PAGE_LISTS_EXP + 1)
|
|
206 #endif /* USE_EXPONENTIAL_USED_LIST_GROWTH */
|
|
207
|
|
208 /* free heap list count */
|
|
209 #define N_FREE_PAGE_LISTS (((FREE_LIST_UPPER_THRESHOLD \
|
|
210 - FREE_LIST_LOWER_THRESHOLD) \
|
|
211 / FREE_LIST_LIN_STEP) \
|
|
212 + FREE_LIST_LOWER_THRESHOLD)
|
|
213
|
|
214
|
|
215 /* Constants for heap address to page header mapping. */
|
|
216 #define LOG_LEVEL2_SIZE 10
|
|
217 #define LEVEL2_SIZE (1 << LOG_LEVEL2_SIZE)
|
|
218 #if BITS_PER_EMACS_INT > 32
|
|
219 # define USE_HASH_TABLE 1
|
|
220 # define LOG_LEVEL1_SIZE 11
|
|
221 #else
|
|
222 # define LOG_LEVEL1_SIZE \
|
|
223 (BITS_PER_EMACS_INT - LOG_LEVEL2_SIZE - LOG_PAGE_SIZE)
|
|
224 #endif
|
|
225 #define LEVEL1_SIZE (1 << LOG_LEVEL1_SIZE)
|
|
226
|
|
227 #ifdef USE_HASH_TABLE
|
|
228 # define HASH(hi) ((hi) & (LEVEL1_SIZE - 1))
|
|
229 # define L1_INDEX(p) HASH ((EMACS_INT) p >> (LOG_LEVEL2_SIZE + LOG_PAGE_SIZE))
|
|
230 #else
|
|
231 # define L1_INDEX(p) ((EMACS_INT) p >> (LOG_LEVEL2_SIZE + LOG_PAGE_SIZE))
|
|
232 #endif
|
|
233 #define L2_INDEX(p) (((EMACS_INT) p >> LOG_PAGE_SIZE) & (LEVEL2_SIZE - 1))
|
|
234
|
|
235
|
|
236
|
|
237
|
|
238 /*--- structs and typedefs ---------------------------------------------*/
|
|
239
|
|
240 /* Links the free lists (mark_bit_free_list, page_header_free_list,
|
|
241 cell free list). */
|
|
242 typedef struct free_link
|
|
243 {
|
|
244 struct lrecord_header lheader;
|
|
245 struct free_link *next_free;
|
|
246 } free_link;
|
|
247
|
|
248
|
|
249 /* Header for pages. They are hold in a doubly linked list. */
|
|
250 typedef struct page_header
|
|
251 {
|
|
252 struct page_header *next; /* next page_header */
|
|
253 struct page_header *prev; /* previous page_header */
|
|
254 /* Field plh holds pointer to the according header of the page list.*/
|
|
255 struct page_list_header *plh; /* page list header */
|
|
256 free_link *free_list; /* links free cells on page */
|
|
257 EMACS_INT n_pages; /* number of pages */
|
|
258 EMACS_INT cell_size; /* size of cells on page */
|
|
259 EMACS_INT cells_on_page; /* total number of cells on page */
|
|
260 EMACS_INT cells_used; /* number of used cells on page */
|
|
261 /* If the number of objects on page is bigger than BITS_PER_EMACS_INT,
|
|
262 the mark bits are put in an extra memory area. Then the field
|
|
263 mark_bits holds the pointer to this area. Is the number of
|
|
264 objects smaller than BITS_PER_EMACS_INT, the mark bits are held in the
|
|
265 mark_bit EMACS_INT directly, without an additional indirection. */
|
|
266 char *mark_bits; /* pointer to mark bits */
|
|
267 void *heap_space; /* pointer to heap, where objects
|
|
268 are stored */
|
|
269 } page_header;
|
|
270
|
|
271
|
|
272 /* Different list types. */
|
|
273 enum list_type_enum {
|
|
274 USED_LIST,
|
|
275 UNMANAGED_LIST,
|
|
276 FREE_LIST
|
|
277 };
|
|
278
|
|
279
|
|
280 /* Header for page lists. Field list_type holds the type of the list. */
|
|
281 typedef struct page_list_header
|
|
282 {
|
|
283 enum list_type_enum list_type; /* the type of the list */
|
|
284 /* Size holds the size of one cell (in bytes) in a used heap list, or the
|
|
285 size of the heap sector (in number of pages). */
|
|
286 size_t size; /* size of one cell / heap sector */
|
|
287 page_header *first; /* first of page_header list */
|
|
288 page_header *last; /* last of page_header list */
|
|
289 /* If the number of objects on page is bigger than
|
|
290 BITS_PER_EMACS_INT, the mark bits are put in an extra memory
|
|
291 area, which is linked in this free list, if not used. Is the
|
|
292 number of objects smaller than BITS_PER_EMACS_INT, the mark bits
|
|
293 are hold in the mark bit EMACS_INT directly, without an
|
|
294 additional indirection. */
|
|
295 free_link *mark_bit_free_list;
|
|
296
|
|
297 #ifdef MEMORY_USAGE_STATS
|
|
298 EMACS_INT page_count; /* number if pages in list */
|
|
299 EMACS_INT used_cells; /* number of objects in list */
|
|
300 EMACS_INT used_space; /* used space */
|
|
301 EMACS_INT total_cells; /* number of available cells */
|
|
302 EMACS_INT total_space; /* available space */
|
|
303 #endif
|
|
304 } page_list_header;
|
|
305
|
|
306
|
|
307 /* The heap sectors are stored with their real start pointer and their
|
|
308 real size. Not aligned to PAGE_SIZE. Needed for freeing heap sectors. */
|
|
309 typedef struct heap_sect {
|
|
310 void *real_start; /* real start pointer (NOT aligned) */
|
|
311 size_t real_size; /* NOT multiple of PAGE_SIZE */
|
|
312 void *start; /* aligned start pointer */
|
|
313 EMACS_INT n_pages; /* multiple of PAGE_SIZE */
|
|
314 } heap_sect;
|
|
315
|
|
316
|
|
317 /* 2nd tree level for mapping of heap addresses to page headers. */
|
|
318 typedef struct level_2_lookup_tree {
|
|
319 page_header *index[LEVEL2_SIZE]; /* link to page header */
|
|
320 EMACS_INT key; /* high order address bits */
|
|
321 #ifdef USE_HASH_TABLE
|
|
322 struct level_2_lookup_tree *hash_link; /* hash chain link */
|
|
323 #endif
|
|
324 } level_2_lookup_tree;
|
|
325
|
|
326
|
|
327
|
|
328 /*--- global variable definitions --------------------------------------*/
|
|
329
|
|
330 /* All global allocator variables are kept in this struct. */
|
|
331 typedef struct mc_allocator_globals_type {
|
|
332
|
|
333 /* heap size */
|
|
334 EMACS_INT heap_size;
|
|
335
|
|
336 /* list of all separatly allocated chunks of heap */
|
|
337 heap_sect heap_sections[MAX_HEAP_SECTS];
|
|
338 EMACS_INT n_heap_sections;
|
|
339
|
|
340 /* Holds all allocated pages, each object size class in its separate list,
|
|
341 to guarantee fast allocation on partially filled pages. */
|
|
342 page_list_header used_heap_pages[N_USED_PAGE_LISTS];
|
|
343
|
|
344 /* Holds all unmanaged pages. */
|
|
345 page_list_header unmanaged_heap_pages[N_UNMANAGED_PAGE_LISTS];
|
|
346
|
|
347 /* Holds all free pages in the heap. N multiples of PAGE_SIZE are
|
|
348 kept on the Nth free list. Contiguos pages are coalesced. */
|
|
349 page_list_header free_heap_pages[N_FREE_PAGE_LISTS];
|
|
350
|
|
351 /* ptr lookup table */
|
|
352 level_2_lookup_tree *ptr_lookup_table[LEVEL1_SIZE];
|
|
353
|
|
354 /* page header free list */
|
|
355 free_link *page_header_free_list;
|
|
356
|
|
357 #ifdef MEMORY_USAGE_STATS
|
|
358 EMACS_INT malloced_bytes;
|
|
359 #endif
|
|
360 } mc_allocator_globals_type;
|
|
361
|
|
362 mc_allocator_globals_type mc_allocator_globals;
|
|
363
|
|
364
|
|
365
|
|
366
|
|
367 /*--- macro accessors --------------------------------------------------*/
|
|
368
|
|
369 #define USED_HEAP_PAGES(i) \
|
|
370 ((page_list_header*) &mc_allocator_globals.used_heap_pages[i])
|
|
371
|
|
372 #define UNMANAGED_HEAP_PAGES(i) \
|
|
373 ((page_list_header*) &mc_allocator_globals.unmanaged_heap_pages[i])
|
|
374
|
|
375 #define FREE_HEAP_PAGES(i) \
|
|
376 ((page_list_header*) &mc_allocator_globals.free_heap_pages[i])
|
|
377
|
|
378 #define PLH(plh) plh
|
|
379 # define PLH_LIST_TYPE(plh) PLH (plh)->list_type
|
|
380 # define PLH_SIZE(plh) PLH (plh)->size
|
|
381 # define PLH_FIRST(plh) PLH (plh)->first
|
|
382 # define PLH_LAST(plh) PLH (plh)->last
|
|
383 # define PLH_MARK_BIT_FREE_LIST(plh) PLH (plh)->mark_bit_free_list
|
|
384 #ifdef MEMORY_USAGE_STATS
|
|
385 # define PLH_PAGE_COUNT(plh) PLH (plh)->page_count
|
|
386 # define PLH_USED_CELLS(plh) PLH (plh)->used_cells
|
|
387 # define PLH_USED_SPACE(plh) PLH (plh)->used_space
|
|
388 # define PLH_TOTAL_CELLS(plh) PLH (plh)->total_cells
|
|
389 # define PLH_TOTAL_SPACE(plh) PLH (plh)->total_space
|
|
390 #endif
|
|
391
|
|
392 #define PH(ph) ph
|
|
393 # define PH_NEXT(ph) PH (ph)->next
|
|
394 # define PH_PREV(ph) PH (ph)->prev
|
|
395 # define PH_PLH(ph) PH (ph)->plh
|
|
396 # define PH_FREE_LIST(ph) PH (ph)->free_list
|
|
397 # define PH_N_PAGES(ph) PH (ph)->n_pages
|
|
398 # define PH_CELL_SIZE(ph) PH (ph)->cell_size
|
|
399 # define PH_CELLS_ON_PAGE(ph) PH (ph)->cells_on_page
|
|
400 # define PH_CELLS_USED(ph) PH (ph)->cells_used
|
|
401 # define PH_MARK_BITS(ph) PH (ph)->mark_bits
|
|
402 # define PH_HEAP_SPACE(ph) PH (ph)->heap_space
|
|
403 #define PH_LIST_TYPE(ph) PLH_LIST_TYPE (PH_PLH (ph))
|
|
404 #define PH_MARK_BIT_FREE_LIST(ph) PLH_MARK_BIT_FREE_LIST (PH_PLH (ph))
|
|
405
|
|
406 #define HEAP_SIZE mc_allocator_globals.heap_size
|
|
407
|
|
408 #ifdef MEMORY_USAGE_STATS
|
|
409 # define MC_MALLOCED_BYTES mc_allocator_globals.malloced_bytes
|
|
410 #endif
|
|
411
|
|
412 #define HEAP_SECTION(index) mc_allocator_globals.heap_sections[index]
|
|
413 #define N_HEAP_SECTIONS mc_allocator_globals.n_heap_sections
|
|
414
|
|
415 #define PAGE_HEADER_FREE_LIST mc_allocator_globals.page_header_free_list
|
|
416
|
|
417 #define NEXT_FREE(free_list) ((free_link*) free_list)->next_free
|
|
418 #define FREE_LIST(free_list) (free_link*) (free_list)
|
|
419
|
|
420 #define PTR_LOOKUP_TABLE(i) mc_allocator_globals.ptr_lookup_table[i]
|
|
421 #define LEVEL2(l2, i) l2->index[i]
|
|
422 # define LEVEL2_KEY(l2) l2->key
|
|
423 #ifdef USE_HASH_TABLE
|
|
424 # define LEVEL2_HASH_LINK(l2) l2->hash_link
|
|
425 #endif
|
|
426
|
|
427 #if ZERO_MEM
|
|
428 # define ZERO_HEAP_SPACE(ph) \
|
|
429 memset (PH_HEAP_SPACE (ph), '\0', PH_N_PAGES (ph) * PAGE_SIZE)
|
|
430 # define ZERO_PAGE_HEADER(ph) memset (ph, '\0', sizeof (page_header))
|
|
431 #endif
|
|
432
|
|
433 #define div_PAGE_SIZE(x) (x >> LOG_PAGE_SIZE)
|
|
434 #define mult_PAGE_SIZE(x) (x << LOG_PAGE_SIZE)
|
|
435
|
|
436 #define BYTES_TO_PAGES(bytes) (div_PAGE_SIZE ((bytes + (PAGE_SIZE - 1))))
|
|
437
|
|
438 #define PAGE_SIZE_ALIGNMENT(address) \
|
|
439 (void *) ((((EMACS_INT) (address)) + PAGE_SIZE) & ~(PAGE_SIZE - 1))
|
|
440
|
|
441 #define PH_ON_FREE_LIST_P(ph) \
|
|
442 (ph && PH_PLH (ph) && (PLH_LIST_TYPE (PH_PLH (ph)) == FREE_LIST))
|
|
443
|
|
444 #define PH_ON_USED_LIST_P(ph) \
|
|
445 (ph && PH_PLH (ph) && (PLH_LIST_TYPE (PH_PLH (ph)) == USED_LIST))
|
|
446
|
|
447 #define PH_ON_UNMANAGED_LIST_P(ph) \
|
|
448 (ph && PH_PLH (ph) && (PLH_LIST_TYPE (PH_PLH (ph)) == UNMANAGED_LIST))
|
|
449
|
|
450
|
|
451
|
|
452
|
|
453 /************************************************************************/
|
|
454 /* MC Allocator */
|
|
455 /************************************************************************/
|
|
456
|
|
457
|
|
458 /* ###TODO### */
|
|
459 #if 1
|
|
460 # define ALLOC_MB_UNMANAGED 1
|
|
461 #endif
|
|
462
|
|
463
|
|
464 /*--- misc functions ---------------------------------------------------*/
|
|
465
|
|
466 /* moved here from alloc.c */
|
|
467 #ifdef ERROR_CHECK_GC
|
|
468 static void
|
|
469 deadbeef_memory (void *ptr, Bytecount size)
|
|
470 {
|
|
471 UINT_32_BIT *ptr4 = (UINT_32_BIT *) ptr;
|
|
472 Bytecount beefs = size >> 2;
|
|
473
|
|
474 /* In practice, size will always be a multiple of four. */
|
|
475 while (beefs--)
|
|
476 (*ptr4++) = 0xDEADBEEF; /* -559038737 base 10 */
|
|
477 }
|
|
478 #endif /* ERROR_CHECK_GC */
|
|
479
|
|
480 /* Visits all pages (page_headers) hooked into the used heap pages
|
|
481 list and executes f with the current page header as
|
|
482 argument. Needed for sweep. */
|
|
483 static void
|
|
484 visit_all_used_page_headers (void (*f) (page_header *ph))
|
|
485 {
|
|
486 int i;
|
|
487 for (i = 0; i < N_USED_PAGE_LISTS; i++)
|
|
488 if (PLH_FIRST (USED_HEAP_PAGES (i)))
|
|
489 {
|
|
490 page_header *ph = PLH_FIRST (USED_HEAP_PAGES (i));
|
|
491 while (PH_NEXT (ph))
|
|
492 {
|
|
493 page_header *next = PH_NEXT (ph); /* in case f removes the page */
|
|
494 f (ph);
|
|
495 ph = next;
|
|
496 }
|
|
497 f (ph);
|
|
498 }
|
|
499 }
|
|
500
|
|
501
|
|
502
|
|
503
|
|
504 /*--- mapping of heap addresses to page headers and mark bits ----------*/
|
|
505
|
|
506 /* Sets a heap pointer and page header pair into the lookup table. */
|
|
507 static void
|
|
508 set_lookup_table (void *ptr, page_header *ph)
|
|
509 {
|
|
510 int l1_index = L1_INDEX (ptr);
|
|
511 level_2_lookup_tree *l2 = PTR_LOOKUP_TABLE (l1_index);
|
|
512 #ifdef USE_HASH_TABLE
|
|
513 while ((l2) && (LEVEL2_KEY (l2) != l1_index))
|
|
514 l2 = LEVEL2_HASH_LINK (l2);
|
|
515 #endif
|
|
516 if (!l2)
|
|
517 {
|
|
518 l2 = (level_2_lookup_tree*)
|
|
519 xmalloc_and_zero (sizeof (level_2_lookup_tree));
|
|
520 #ifdef MEMORY_USAGE_STATS
|
|
521 MC_MALLOCED_BYTES +=
|
|
522 malloced_storage_size (0, sizeof (level_2_lookup_tree), 0);
|
|
523 #endif
|
|
524 memset (l2, 0, sizeof (level_2_lookup_tree));
|
|
525 #ifdef USE_HASH_TABLE
|
|
526 LEVEL2_HASH_LINK (l2) = PTR_LOOKUP_TABLE (l1_index);
|
|
527 #endif
|
|
528 PTR_LOOKUP_TABLE (l1_index) = l2;
|
|
529 LEVEL2_KEY (l2) = l1_index;
|
|
530 }
|
|
531 LEVEL2 (l2, L2_INDEX (ptr)) = ph;
|
|
532 }
|
|
533
|
|
534
|
|
535 #ifdef UNSET_LOOKUP_TABLE
|
|
536 /* Set the lookup table to 0 for given heap address. */
|
|
537 static void
|
|
538 unset_lookup_table (void *ptr)
|
|
539 {
|
|
540 int l1_index = L1_INDEX (ptr);
|
|
541 level_2_lookup_tree *l2 = PTR_LOOKUP_TABLE (l1_index);
|
|
542 #ifdef USE_HASH_TABLE
|
|
543 while ((l2) && (LEVEL2_KEY (l2) != l1_index))
|
|
544 l2 = LEVEL2_HASH_LINK (l2);
|
|
545 #endif
|
|
546 if (l2) {
|
|
547 LEVEL2 (l2, L2_INDEX (ptr)) = 0;
|
|
548 }
|
|
549 }
|
|
550 #endif
|
|
551
|
|
552 /* Returns the page header of a given heap address, or 0 if not in table.
|
|
553 For internal use, no error checking. */
|
|
554 static page_header *
|
|
555 get_page_header_internal (void *ptr)
|
|
556 {
|
|
557 int l1_index = L1_INDEX (ptr);
|
|
558 level_2_lookup_tree *l2 = PTR_LOOKUP_TABLE (l1_index);
|
|
559 #ifdef USE_HASH_TABLE
|
|
560 while ((l2) && (LEVEL2_KEY (l2) != l1_index))
|
|
561 l2 = LEVEL2_HASH_LINK (l2);
|
|
562 #endif
|
|
563 if (!l2)
|
|
564 return 0;
|
|
565 return LEVEL2 (l2, L2_INDEX (ptr));
|
|
566 }
|
|
567
|
|
568 /* Returns the page header of a given heap address, or 0 if not in table. */
|
|
569 static page_header *
|
|
570 get_page_header (void *ptr)
|
|
571 {
|
|
572 int l1_index = L1_INDEX (ptr);
|
|
573 level_2_lookup_tree *l2 = PTR_LOOKUP_TABLE (l1_index);
|
|
574 #ifdef USE_HASH_TABLE
|
|
575 while ((l2) && (LEVEL2_KEY (l2) != l1_index))
|
|
576 l2 = LEVEL2_HASH_LINK (l2);
|
|
577 #endif
|
|
578 assert (l2 && LEVEL2 (l2, L2_INDEX (ptr)));
|
|
579 return LEVEL2 (l2, L2_INDEX (ptr));
|
|
580 }
|
|
581
|
|
582
|
|
583 /* Returns the mark bit index of a given heap address. */
|
|
584 static EMACS_INT
|
|
585 get_mark_bit_index (void *ptr, page_header *ph)
|
|
586 {
|
|
587 EMACS_INT cell_size = PH_CELL_SIZE (ph);
|
|
588 if (cell_size)
|
|
589 return (((EMACS_INT) ptr - (EMACS_INT)(PH_HEAP_SPACE (ph))) / cell_size);
|
|
590 else /* only one object on page */
|
|
591 return 0;
|
|
592 }
|
|
593
|
|
594
|
|
595 /* Adds addresses of pages to lookup table. */
|
|
596 static void
|
|
597 add_pages_to_lookup_table (page_header *ph, EMACS_INT n_pages)
|
|
598 {
|
|
599 char *p = (char*) PH_HEAP_SPACE (ph);
|
|
600 EMACS_INT end_of_section = (EMACS_INT) p + (PAGE_SIZE * n_pages);
|
|
601 for (p = (char*) PH_HEAP_SPACE (ph);
|
|
602 (EMACS_INT) p < end_of_section; p += PAGE_SIZE)
|
|
603 set_lookup_table (p, ph);
|
|
604 }
|
|
605
|
|
606
|
|
607 /* Initializes lookup table. */
|
|
608 static void
|
|
609 init_lookup_table (void)
|
|
610 {
|
|
611 int i;
|
|
612 for (i = 0; i < LEVEL1_SIZE; i++)
|
|
613 PTR_LOOKUP_TABLE (i) = 0;
|
|
614 }
|
|
615
|
|
616
|
|
617
|
|
618
|
|
619 /*--- mark bits --------------------------------------------------------*/
|
|
620
|
|
621 /* Number of mark bits: minimum 1, maximum 8. */
|
|
622 #define N_MARK_BITS 1
|
|
623
|
|
624 /*--- bit operations --- */
|
|
625
|
|
626 /* Allocates a bit array of length bits. */
|
|
627 static char *
|
|
628 alloc_bit_array(size_t bits)
|
|
629 {
|
|
630 #ifdef ALLOC_MB_UNMANAGED
|
|
631 size_t size = ((bits + CHAR_BIT - 1) / CHAR_BIT) * sizeof(char);
|
|
632 if (size < sizeof (free_link)) size = sizeof (free_link);
|
|
633 return (char *) mc_alloc_unmanaged (size);
|
|
634 #else /* not ALLOC_MB_UNMANAGED */
|
|
635 size_t size = ((bits + CHAR_BIT - 1) / CHAR_BIT) * sizeof(char);
|
|
636 char *bit_array;
|
|
637 if (size < sizeof (free_link)) size = sizeof (free_link);
|
|
638 bit_array = (char*) xmalloc_and_zero (size);
|
|
639 #ifdef MEMORY_USAGE_STATS
|
|
640 MC_MALLOCED_BYTES += malloced_storage_size (0, size, 0);
|
|
641 #endif
|
|
642 return bit_array;
|
|
643 #endif /* not ALLOC_MB_UNMANAGED */
|
|
644 }
|
|
645
|
|
646
|
|
647 /* Returns the bit value at pos. */
|
|
648 static EMACS_INT
|
|
649 get_bit (char *bit_array, EMACS_INT pos)
|
|
650 {
|
|
651 #if N_MARK_BITS > 1
|
|
652 EMACS_INT result = 0;
|
|
653 EMACS_INT i;
|
|
654 #endif
|
|
655 bit_array += pos / CHAR_BIT;
|
|
656 #if N_MARK_BITS > 1
|
|
657 for (i = 0; i < N_MARK_BITS; i++)
|
|
658 result |= (*bit_array & (1 << ((pos + i) % CHAR_BIT)));
|
|
659 return result >> pos;
|
|
660 #else
|
|
661 return (*bit_array & (1 << (pos % CHAR_BIT))) != 0;
|
|
662 #endif
|
|
663 }
|
|
664
|
|
665
|
|
666 /* Bit_Arrays bit at pos to val. */
|
|
667 static void
|
|
668 set_bit(char *bit_array, EMACS_INT pos, EMACS_INT val)
|
|
669 {
|
|
670 #if N_MARK_BITS > 1
|
|
671 EMACS_INT result = 0;
|
|
672 EMACS_INT i;
|
|
673 #endif
|
|
674 bit_array += pos / CHAR_BIT;
|
|
675 #if N_MARK_BITS > 1
|
|
676 for (i = 0; i < N_MARK_BITS; i++)
|
|
677 if ((val >> i) & 1)
|
|
678 *bit_array |= 1 << ((pos + i) % CHAR_BIT);
|
|
679 else
|
|
680 *bit_array &= ~(1 << ((pos + i) % CHAR_BIT));
|
|
681 #else
|
|
682 if (val)
|
|
683 *bit_array |= 1 << (pos % CHAR_BIT);
|
|
684 else
|
|
685 *bit_array &= ~(1 << (pos % CHAR_BIT));
|
|
686 #endif
|
|
687 }
|
|
688
|
|
689
|
|
690 /*--- mark bit functions ---*/
|
|
691 #define USE_PNTR_MARK_BITS(ph) (PH_CELLS_ON_PAGE (ph) > BITS_PER_EMACS_INT)
|
|
692 #define USE_WORD_MARK_BITS(ph) (PH_CELLS_ON_PAGE (ph) <= BITS_PER_EMACS_INT)
|
|
693
|
|
694 #define GET_BIT_WORD(b, p) get_bit ((char*) &b, p)
|
|
695 #define GET_BIT_PNTR(b, p) get_bit (b, p)
|
|
696
|
|
697 #define SET_BIT_WORD(b, p, v) set_bit ((char*) &b, p, v)
|
|
698 #define SET_BIT_PNTR(b, p, v) set_bit (b, p, v)
|
|
699
|
|
700 #define ZERO_MARK_BITS_WORD(ph) PH_MARK_BITS (ph) = 0
|
|
701 #define ZERO_MARK_BITS_PNTR(ph) \
|
|
702 do { \
|
|
703 memset (PH_MARK_BITS (ph), '\0', \
|
|
704 (PH_CELLS_ON_PAGE (ph) + CHAR_BIT - 1) \
|
|
705 / CHAR_BIT * sizeof(char)); \
|
|
706 } while (0)
|
|
707
|
|
708 #define GET_BIT(bit, ph, p) \
|
|
709 do { \
|
|
710 if (USE_PNTR_MARK_BITS (ph)) \
|
|
711 bit = GET_BIT_PNTR (PH_MARK_BITS (ph), p); \
|
|
712 else \
|
|
713 bit = GET_BIT_WORD (PH_MARK_BITS (ph), p); \
|
|
714 } while (0)
|
|
715
|
|
716 #define SET_BIT(ph, p, v) \
|
|
717 do { \
|
|
718 if (USE_PNTR_MARK_BITS (ph)) \
|
|
719 SET_BIT_PNTR (PH_MARK_BITS (ph), p, v); \
|
|
720 else \
|
|
721 SET_BIT_WORD (PH_MARK_BITS (ph), p, v); \
|
|
722 } while (0)
|
|
723
|
|
724 #define ZERO_MARK_BITS(ph) \
|
|
725 do { \
|
|
726 if (USE_PNTR_MARK_BITS (ph)) \
|
|
727 ZERO_MARK_BITS_PNTR (ph); \
|
|
728 else \
|
|
729 ZERO_MARK_BITS_WORD (ph); \
|
|
730 } while (0)
|
|
731
|
|
732
|
|
733 /* Allocates mark-bit space either from a free list or from the OS
|
|
734 for the given page header. */
|
|
735 static char *
|
|
736 alloc_mark_bits (page_header *ph)
|
|
737 {
|
|
738 char *result;
|
|
739 if (PH_MARK_BIT_FREE_LIST (ph) == 0)
|
|
740 result = (char*) alloc_bit_array (PH_CELLS_ON_PAGE (ph) * N_MARK_BITS);
|
|
741 else
|
|
742 {
|
|
743 result = (char*) PH_MARK_BIT_FREE_LIST (ph);
|
|
744 PH_MARK_BIT_FREE_LIST (ph) = NEXT_FREE (result);
|
|
745 }
|
|
746 return result;
|
|
747 }
|
|
748
|
|
749
|
|
750 /* Frees by maintaining a free list. */
|
|
751 static void
|
|
752 free_mark_bits (page_header *ph)
|
|
753 {
|
|
754 #ifdef ALLOC_MB_UNMANAGED
|
|
755 if (PH_MARK_BITS (ph))
|
|
756 mc_free (PH_MARK_BITS (ph));
|
|
757 #else /* not ALLOC_MB_UNMANAGED */
|
|
758 if (PH_MARK_BITS (ph)) {
|
|
759 NEXT_FREE (PH_MARK_BITS (ph)) = PH_MARK_BIT_FREE_LIST (ph);
|
|
760 PH_MARK_BIT_FREE_LIST (ph) = FREE_LIST (PH_MARK_BITS (ph));
|
|
761 }
|
|
762 #endif /* not ALLOC_MB_UNMANAGED */
|
|
763 }
|
|
764
|
|
765
|
|
766 /* Installs mark bits and zeros bits. */
|
|
767 static void
|
|
768 install_mark_bits (page_header *ph)
|
|
769 {
|
|
770 if (USE_PNTR_MARK_BITS (ph))
|
|
771 {
|
|
772 PH_MARK_BITS (ph) = alloc_mark_bits (ph);
|
|
773 ZERO_MARK_BITS_PNTR (ph);
|
|
774 }
|
|
775 else
|
|
776 ZERO_MARK_BITS_WORD (ph);
|
|
777 }
|
|
778
|
|
779
|
|
780 /* Cleans and frees the mark bits of the given page_header. */
|
|
781 static void
|
|
782 remove_mark_bits (page_header *ph)
|
|
783 {
|
|
784 if (USE_PNTR_MARK_BITS (ph))
|
|
785 free_mark_bits (ph);
|
|
786 }
|
|
787
|
|
788
|
|
789 /* Zeros all mark bits in given header. */
|
|
790 static void
|
|
791 zero_mark_bits (page_header *ph)
|
|
792 {
|
|
793 ZERO_MARK_BITS (ph);
|
|
794 }
|
|
795
|
|
796
|
|
797 /* Returns mark bit for given heap pointer. */
|
|
798 EMACS_INT
|
|
799 get_mark_bit (void *ptr)
|
|
800 {
|
|
801 EMACS_INT bit = 0;
|
|
802 page_header *ph = get_page_header (ptr);
|
|
803 gc_checking_assert (ph && PH_ON_USED_LIST_P (ph));
|
|
804 if (ph)
|
|
805 {
|
|
806 GET_BIT (bit, ph, get_mark_bit_index (ptr, ph));
|
|
807 }
|
|
808 return bit;
|
|
809 }
|
|
810
|
|
811
|
|
812 /* Sets mark bit for given heap pointer. */
|
|
813 void
|
|
814 set_mark_bit (void *ptr, EMACS_INT value)
|
|
815 {
|
|
816 page_header *ph = get_page_header (ptr);
|
|
817 assert (ph && PH_ON_USED_LIST_P (ph));
|
|
818 if (ph)
|
|
819 {
|
|
820 SET_BIT (ph, get_mark_bit_index (ptr, ph), value);
|
|
821 }
|
|
822 }
|
|
823
|
|
824
|
|
825
|
|
826
|
|
827 /*--- page header functions --------------------------------------------*/
|
|
828
|
|
829 /* Allocates a page header either from a free list or from the OS. */
|
|
830 static page_header *
|
|
831 alloc_page_header (void)
|
|
832 {
|
|
833 page_header *result;
|
|
834 if (PAGE_HEADER_FREE_LIST == 0)
|
|
835 {
|
|
836 result =
|
|
837 (page_header *) xmalloc_and_zero ((EMACS_INT) (sizeof (page_header)));
|
|
838 #ifdef MEMORY_USAGE_STATS
|
|
839 MC_MALLOCED_BYTES += malloced_storage_size (0, sizeof (page_header), 0);
|
|
840 #endif
|
|
841
|
|
842 }
|
|
843 else
|
|
844 {
|
|
845 result = (page_header*) PAGE_HEADER_FREE_LIST;
|
|
846 PAGE_HEADER_FREE_LIST = NEXT_FREE (result);
|
|
847 }
|
|
848 return result;
|
|
849 }
|
|
850
|
|
851
|
|
852 /* Frees given page header by maintaining a free list. */
|
|
853 static void
|
|
854 free_page_header (page_header *ph)
|
|
855 {
|
|
856 #if ZERO_MEM
|
|
857 ZERO_PAGE_HEADER (ph);
|
|
858 #endif
|
|
859 NEXT_FREE (ph) = PAGE_HEADER_FREE_LIST;
|
|
860 PAGE_HEADER_FREE_LIST = FREE_LIST (ph);
|
|
861 }
|
|
862
|
|
863
|
|
864 /* Adds given page header to given page list header's list. */
|
|
865 static void
|
|
866 add_page_header_to_plh (page_header *ph, page_list_header *plh)
|
|
867 {
|
|
868 /* insert at the front of the list */
|
|
869 PH_PREV (ph) = 0;
|
|
870 PH_NEXT (ph) = PLH_FIRST (plh);
|
|
871 PH_PLH (ph) = plh;
|
|
872 /* if list is not empty, set prev in the first element */
|
|
873 if (PLH_FIRST (plh))
|
|
874 PH_PREV (PLH_FIRST (plh)) = ph;
|
|
875 /* one element in list is first and last at the same time */
|
|
876 PLH_FIRST (plh) = ph;
|
|
877 if (!PLH_LAST (plh))
|
|
878 PLH_LAST (plh) = ph;
|
|
879
|
|
880 #ifdef MEMORY_USAGE_STATS
|
|
881 /* bump page count */
|
|
882 PLH_PAGE_COUNT (plh)++;
|
|
883 #endif
|
|
884
|
|
885 }
|
|
886
|
|
887
|
|
888 /* Removes given page header from given page list header's list. */
|
|
889 static void
|
|
890 remove_page_header_from_plh (page_header *ph, page_list_header *plh)
|
|
891 {
|
|
892 if (PLH_FIRST (plh) == ph)
|
|
893 PLH_FIRST (plh) = PH_NEXT (ph);
|
|
894 if (PLH_LAST (plh) == ph)
|
|
895 PLH_LAST (plh) = PH_PREV (ph);
|
|
896 if (PH_NEXT (ph))
|
|
897 PH_PREV (PH_NEXT (ph)) = PH_PREV (ph);
|
|
898 if (PH_PREV (ph))
|
|
899 PH_NEXT (PH_PREV (ph)) = PH_NEXT (ph);
|
|
900
|
|
901 #ifdef MEMORY_USAGE_STATS
|
|
902 /* decrease page count */
|
|
903 PLH_PAGE_COUNT (plh)--;
|
|
904 #endif
|
|
905 }
|
|
906
|
|
907
|
|
908 /* Moves a page header to the front of its the page header list.
|
|
909 This is used during sweep: Pages with some alive objects are moved to
|
|
910 the front. This makes allocation faster, all pages with free slots
|
|
911 can be found at the front of the list. */
|
|
912 static void
|
|
913 move_page_header_to_front (page_header *ph)
|
|
914 {
|
|
915 page_list_header *plh = PH_PLH (ph);
|
|
916 /* is page already first? */
|
|
917 if (ph == PLH_FIRST (plh)) return;
|
|
918 /* remove from list */
|
|
919 if (PLH_LAST (plh) == ph)
|
|
920 PLH_LAST (plh) = PH_PREV (ph);
|
|
921 if (PH_NEXT (ph))
|
|
922 PH_PREV (PH_NEXT (ph)) = PH_PREV (ph);
|
|
923 if (PH_PREV (ph))
|
|
924 PH_NEXT (PH_PREV (ph)) = PH_NEXT (ph);
|
|
925 /* insert at the front */
|
|
926 PH_NEXT (ph) = PLH_FIRST (plh);
|
|
927 PH_PREV (ph) = 0;
|
|
928 PH_PREV (PH_NEXT (ph)) = ph;
|
|
929 PLH_FIRST (plh) = ph;
|
|
930 }
|
|
931
|
|
932
|
|
933
|
|
934
|
|
935 /*--- page list functions ----------------------------------------------*/
|
|
936
|
|
937 /* Returns the index of the used heap list according to given size. */
|
|
938 static int
|
|
939 get_used_list_index (size_t size)
|
|
940 {
|
|
941 if (size <= USED_LIST_MIN_OBJECT_SIZE)
|
|
942 return 0;
|
|
943 if (size <= USED_LIST_UPPER_THRESHOLD)
|
|
944 return ((size - USED_LIST_MIN_OBJECT_SIZE - 1)
|
|
945 / USED_LIST_LIN_STEP) + 1;
|
|
946 return N_USED_PAGE_LISTS - 1;
|
|
947 }
|
|
948
|
|
949
|
|
950 /* Returns the size of the used heap list according to given index. */
|
|
951 static size_t
|
|
952 get_used_list_size_value (int used_index)
|
|
953 {
|
|
954 if (used_index < N_USED_PAGE_LISTS - 1)
|
|
955 return (used_index * USED_LIST_LIN_STEP) + USED_LIST_MIN_OBJECT_SIZE;
|
|
956 return 0;
|
|
957 }
|
|
958
|
|
959
|
|
960 /* Returns the index of the used heap list according to given size. */
|
|
961 static int
|
|
962 get_unmanaged_list_index (size_t size)
|
|
963 {
|
|
964 if (size <= UNMANAGED_LIST_MIN_OBJECT_SIZE)
|
|
965 return 0;
|
|
966 if (size <= UNMANAGED_LIST_UPPER_THRESHOLD)
|
|
967 return ((size - UNMANAGED_LIST_MIN_OBJECT_SIZE - 1)
|
|
968 / UNMANAGED_LIST_LIN_STEP) + 1;
|
|
969 return N_UNMANAGED_PAGE_LISTS - 1;
|
|
970 }
|
|
971
|
|
972
|
|
973 /* Returns the size of the unmanaged heap list according to given index. */
|
|
974 static size_t
|
|
975 get_unmanaged_list_size_value (int unmanaged_index)
|
|
976 {
|
|
977 if (unmanaged_index < N_UNMANAGED_PAGE_LISTS - 1)
|
|
978 return (unmanaged_index * UNMANAGED_LIST_LIN_STEP)
|
|
979 + UNMANAGED_LIST_MIN_OBJECT_SIZE;
|
|
980 return 0;
|
|
981 }
|
|
982
|
|
983
|
|
984 /* Returns the index of the free heap list according to given size. */
|
|
985 static int
|
|
986 get_free_list_index (EMACS_INT n_pages)
|
|
987 {
|
|
988 if (n_pages == 0)
|
|
989 return 0;
|
|
990 if (n_pages <= FREE_LIST_LOWER_THRESHOLD)
|
|
991 return n_pages - 1;
|
|
992 if (n_pages >= FREE_LIST_UPPER_THRESHOLD - 1)
|
|
993 return N_FREE_PAGE_LISTS - 1;
|
|
994 return ((n_pages - FREE_LIST_LOWER_THRESHOLD - 1)
|
|
995 / FREE_LIST_LIN_STEP) + FREE_LIST_LOWER_THRESHOLD;
|
|
996
|
|
997 }
|
|
998
|
|
999
|
|
1000 /* Returns the size in number of pages of the given free list at index. */
|
|
1001 static size_t
|
|
1002 get_free_list_size_value (int free_index)
|
|
1003 {
|
|
1004 if (free_index < FREE_LIST_LOWER_THRESHOLD)
|
|
1005 return free_index + 1;
|
|
1006 if (free_index >= N_FREE_PAGE_LISTS)
|
|
1007 return FREE_LIST_UPPER_THRESHOLD;
|
|
1008 return ((free_index + 1 - FREE_LIST_LOWER_THRESHOLD)
|
|
1009 * FREE_LIST_LIN_STEP) + FREE_LIST_LOWER_THRESHOLD;
|
|
1010 }
|
|
1011
|
|
1012
|
|
1013 #ifdef MEMORY_USAGE_STATS
|
|
1014 Bytecount
|
|
1015 mc_alloced_storage_size (Bytecount claimed_size, struct overhead_stats *stats)
|
|
1016 {
|
|
1017 size_t used_size =
|
|
1018 get_used_list_size_value (get_used_list_index (claimed_size));
|
|
1019 if (used_size == 0)
|
|
1020 used_size = mult_PAGE_SIZE (BYTES_TO_PAGES (claimed_size));
|
|
1021
|
|
1022 if (stats)
|
|
1023 {
|
|
1024 stats->was_requested += claimed_size;
|
|
1025 stats->malloc_overhead += used_size - claimed_size;
|
|
1026 }
|
|
1027
|
|
1028 return used_size;
|
|
1029 }
|
|
1030 #endif /* not MEMORY_USAGE_STATS */
|
|
1031
|
|
1032
|
|
1033
|
|
1034 /*--- free heap functions ----------------------------------------------*/
|
|
1035
|
|
1036 /* Frees a heap section, if the heap_section is completly free */
|
|
1037 static EMACS_INT
|
|
1038 free_heap_section (page_header *ph)
|
|
1039 {
|
|
1040 int i;
|
|
1041 int removed = 0;
|
|
1042 for (i = 0; i < N_HEAP_SECTIONS; i++)
|
|
1043 if (!removed)
|
|
1044 {
|
|
1045 if ((PH_HEAP_SPACE (ph) == HEAP_SECTION(i).start)
|
|
1046 && (PH_N_PAGES (ph) == HEAP_SECTION(i).n_pages))
|
|
1047 {
|
|
1048 xfree_1 (HEAP_SECTION(i).real_start);
|
|
1049 #ifdef MEMORY_USAGE_STATS
|
|
1050 MC_MALLOCED_BYTES
|
|
1051 -= malloced_storage_size (0, HEAP_SECTION(i).real_size, 0);
|
|
1052 #endif
|
|
1053
|
|
1054 HEAP_SIZE -= PH_N_PAGES (ph) * PAGE_SIZE;
|
|
1055
|
|
1056 removed = 1;
|
|
1057 }
|
|
1058 }
|
|
1059 else
|
|
1060 {
|
|
1061 HEAP_SECTION(i-1).real_start = HEAP_SECTION(i).real_start;
|
|
1062 HEAP_SECTION(i-1).real_size = HEAP_SECTION(i).real_size;
|
|
1063 HEAP_SECTION(i-1).start = HEAP_SECTION(i).start;
|
|
1064 HEAP_SECTION(i-1).n_pages = HEAP_SECTION(i).n_pages;
|
|
1065 }
|
|
1066
|
|
1067 N_HEAP_SECTIONS = N_HEAP_SECTIONS - removed;
|
|
1068
|
|
1069 return removed;
|
|
1070 }
|
|
1071
|
|
1072 /* Removes page from free list. */
|
|
1073 static void
|
|
1074 remove_page_from_free_list (page_header *ph)
|
|
1075 {
|
|
1076 remove_page_header_from_plh (ph, PH_PLH (ph));
|
|
1077 PH_PLH (ph) = 0;
|
|
1078 }
|
|
1079
|
|
1080
|
|
1081 /* Adds page to according free list. */
|
|
1082 static void
|
|
1083 add_page_to_free_list (page_header *ph)
|
|
1084 {
|
|
1085 PH_PLH (ph) = FREE_HEAP_PAGES (get_free_list_index (PH_N_PAGES (ph)));
|
|
1086 add_page_header_to_plh (ph, PH_PLH (ph));
|
|
1087 }
|
|
1088
|
|
1089
|
|
1090 /* Merges two adjacent pages. */
|
|
1091 static page_header *
|
|
1092 merge_pages (page_header *first_ph, page_header *second_ph)
|
|
1093 {
|
|
1094 /* merge */
|
|
1095 PH_N_PAGES (first_ph) += PH_N_PAGES (second_ph);
|
|
1096 /* clean up left over page header */
|
|
1097 free_page_header (second_ph);
|
|
1098 /* update lookup table */
|
|
1099 add_pages_to_lookup_table (first_ph, PH_N_PAGES (first_ph));
|
|
1100
|
|
1101 return first_ph;
|
|
1102 }
|
|
1103
|
|
1104
|
|
1105 /* Checks if pages are adjacent, merges them, and adds merged page to
|
|
1106 free list */
|
|
1107 static void
|
|
1108 merge_into_free_list (page_header *ph)
|
|
1109 {
|
|
1110 /* check if you can coalesce adjacent pages */
|
|
1111 page_header *prev_ph =
|
|
1112 get_page_header_internal ((void*) (((EMACS_INT) PH_HEAP_SPACE (ph))
|
|
1113 - PAGE_SIZE));
|
|
1114 page_header *succ_ph =
|
|
1115 get_page_header_internal ((void*) (((EMACS_INT) PH_HEAP_SPACE (ph))
|
|
1116 + (PH_N_PAGES (ph) * PAGE_SIZE)));
|
|
1117 if (PH_ON_FREE_LIST_P (prev_ph))
|
|
1118 {
|
|
1119 remove_page_from_free_list (prev_ph);
|
|
1120 ph = merge_pages (prev_ph, ph);
|
|
1121 }
|
|
1122 if (PH_ON_FREE_LIST_P (succ_ph))
|
|
1123 {
|
|
1124 remove_page_from_free_list (succ_ph);
|
|
1125 ph = merge_pages (ph, succ_ph);
|
|
1126 }
|
|
1127 /* try to free heap_section, if the section is complete */
|
|
1128 if (!free_heap_section (ph))
|
|
1129 /* else add merged page to free list */
|
|
1130 add_page_to_free_list (ph);
|
|
1131 }
|
|
1132
|
|
1133
|
|
1134 /* Cuts given page header after n_pages, returns the first (cut) part, and
|
|
1135 puts the rest on the free list. */
|
|
1136 static page_header *
|
|
1137 split_page (page_header *ph, EMACS_INT n_pages)
|
|
1138 {
|
|
1139 page_header *new_ph;
|
|
1140 EMACS_INT rem_pages = PH_N_PAGES (ph) - n_pages;
|
|
1141
|
|
1142 /* remove the page from the free list if already hooked in */
|
|
1143 if (PH_PLH (ph))
|
|
1144 remove_page_from_free_list (ph);
|
|
1145 /* set new number of pages */
|
|
1146 PH_N_PAGES (ph) = n_pages;
|
|
1147 /* add new page to lookup table */
|
|
1148 add_pages_to_lookup_table (ph, n_pages);
|
|
1149
|
|
1150 if (rem_pages)
|
|
1151 {
|
|
1152 /* build new page with reminder */
|
|
1153 new_ph = alloc_page_header ();
|
|
1154 PH_N_PAGES (new_ph) = rem_pages;
|
|
1155 PH_HEAP_SPACE (new_ph) =
|
|
1156 (void*) ((EMACS_INT) (PH_HEAP_SPACE (ph)) + (n_pages * PAGE_SIZE));
|
|
1157 /* add new page to lookup table */
|
|
1158 add_pages_to_lookup_table (new_ph, rem_pages);
|
|
1159 /* hook the rest into free list */
|
|
1160 add_page_to_free_list (new_ph);
|
|
1161 }
|
|
1162 return ph;
|
|
1163 }
|
|
1164
|
|
1165
|
|
1166 /* Expands the heap by given number of pages. */
|
|
1167 static page_header *
|
|
1168 expand_heap (EMACS_INT needed_pages)
|
|
1169 {
|
|
1170 page_header *ph;
|
|
1171 EMACS_INT n_pages;
|
|
1172 size_t real_size;
|
|
1173 void *real_start;
|
|
1174
|
|
1175 /* determine number of pages the heap should grow */
|
|
1176 n_pages = needed_pages + (HEAP_SIZE / (PAGE_SIZE * HEAP_GROWTH_DIVISOR));
|
|
1177 if (n_pages < MIN_HEAP_INCREASE)
|
|
1178 n_pages = MIN_HEAP_INCREASE;
|
|
1179
|
|
1180 /* get the real values */
|
|
1181 real_size = (n_pages * PAGE_SIZE) + PAGE_SIZE;
|
|
1182 real_start = xmalloc_and_zero (real_size);
|
|
1183 #ifdef MEMORY_USAGE_STATS
|
|
1184 MC_MALLOCED_BYTES += malloced_storage_size (0, real_size, 0);
|
|
1185 #endif
|
|
1186
|
|
1187 /* maintain heap section count */
|
|
1188 if (N_HEAP_SECTIONS >= MAX_HEAP_SECTS)
|
|
1189 {
|
|
1190 stderr_out ("Increase number of MAX_HEAP_SECTS");
|
|
1191 ABORT ();
|
|
1192 }
|
|
1193 HEAP_SECTION(N_HEAP_SECTIONS).real_start = real_start;
|
|
1194 HEAP_SECTION(N_HEAP_SECTIONS).real_size = real_size;
|
|
1195 HEAP_SECTION(N_HEAP_SECTIONS).start = PAGE_SIZE_ALIGNMENT (real_start);
|
|
1196 HEAP_SECTION(N_HEAP_SECTIONS).n_pages = n_pages;
|
|
1197 N_HEAP_SECTIONS ++;
|
|
1198
|
|
1199 /* get page header */
|
|
1200 ph = alloc_page_header ();
|
|
1201
|
|
1202 /* setup page header */
|
|
1203 PH_N_PAGES (ph) = n_pages;
|
|
1204 PH_HEAP_SPACE (ph) = PAGE_SIZE_ALIGNMENT (real_start);
|
|
1205 assert (((EMACS_INT) (PH_HEAP_SPACE (ph)) % PAGE_SIZE) == 0);
|
|
1206 HEAP_SIZE += n_pages * PAGE_SIZE;
|
|
1207
|
|
1208 /* this was also done by allocate_lisp_storage */
|
|
1209 if (need_to_check_c_alloca)
|
|
1210 xemacs_c_alloca (0);
|
|
1211
|
|
1212 /* return needed size, put rest on free list */
|
|
1213 return split_page (ph, needed_pages);
|
|
1214 }
|
|
1215
|
|
1216
|
|
1217
|
|
1218
|
|
1219 /*--- used heap functions ----------------------------------------------*/
|
|
1220 /* Installs initial free list. */
|
|
1221 static void
|
|
1222 install_cell_free_list (page_header *ph)
|
|
1223 {
|
|
1224 char *p;
|
|
1225 int i;
|
|
1226 EMACS_INT cell_size = PH_CELL_SIZE (ph);
|
|
1227 /* write initial free list if cell_size is < PAGE_SIZE */
|
|
1228 p = (char *) PH_HEAP_SPACE (ph);
|
|
1229 for (i = 0; i < PH_CELLS_ON_PAGE (ph) - 1; i++)
|
|
1230 {
|
|
1231 #ifdef ERROR_CHECK_GC
|
|
1232 assert (!LRECORD_FREE_P (p));
|
|
1233 MARK_LRECORD_AS_FREE (p);
|
|
1234 #endif
|
|
1235 NEXT_FREE (p) = FREE_LIST (p + cell_size);
|
|
1236 set_lookup_table (p, ph);
|
|
1237 p += cell_size;
|
|
1238 }
|
|
1239 #ifdef ERROR_CHECK_GC
|
|
1240 assert (!LRECORD_FREE_P (p));
|
|
1241 MARK_LRECORD_AS_FREE (p);
|
|
1242 #endif
|
|
1243 NEXT_FREE (p) = 0;
|
|
1244 set_lookup_table (p, ph);
|
|
1245
|
|
1246 /* hook free list into header */
|
|
1247 PH_FREE_LIST (ph) = FREE_LIST (PH_HEAP_SPACE (ph));
|
|
1248 }
|
|
1249
|
|
1250
|
|
1251 /* Cleans the object space of the given page_header. */
|
|
1252 static void
|
|
1253 remove_cell_free_list (page_header *ph)
|
|
1254 {
|
|
1255 #if ZERO_MEM
|
|
1256 ZERO_HEAP_SPACE (ph);
|
|
1257 #endif
|
|
1258 PH_FREE_LIST (ph) = 0;
|
|
1259 }
|
|
1260
|
|
1261
|
|
1262 /* Installs a new page and hooks it into given page_list_header. */
|
|
1263 static page_header *
|
|
1264 install_page_in_used_list (page_header *ph, page_list_header *plh,
|
|
1265 size_t size, int managed)
|
|
1266 {
|
|
1267 /* add to list */
|
|
1268 add_page_header_to_plh (ph, plh);
|
|
1269
|
|
1270 /* determine cell size */
|
|
1271 if (PLH_SIZE (plh))
|
|
1272 PH_CELL_SIZE (ph) = PLH_SIZE (plh);
|
|
1273 else
|
|
1274 PH_CELL_SIZE (ph) = size;
|
|
1275 PH_CELLS_ON_PAGE (ph) = (PAGE_SIZE * PH_N_PAGES (ph)) / PH_CELL_SIZE (ph);
|
|
1276
|
|
1277 /* init cell count */
|
|
1278 PH_CELLS_USED (ph) = 0;
|
|
1279
|
|
1280 /* install mark bits and initialize cell free list */
|
|
1281 if (managed)
|
|
1282 install_mark_bits (ph);
|
|
1283
|
|
1284 install_cell_free_list (ph);
|
|
1285
|
|
1286 #ifdef MEMORY_USAGE_STATS
|
|
1287 PLH_TOTAL_CELLS (plh) += PH_CELLS_ON_PAGE (ph);
|
|
1288 PLH_TOTAL_SPACE (plh) += PAGE_SIZE * PH_N_PAGES (ph);
|
|
1289 #endif
|
|
1290
|
|
1291 return ph;
|
|
1292 }
|
|
1293
|
|
1294
|
|
1295 /* Cleans and frees a page, identified by the given page_header. */
|
|
1296 static void
|
|
1297 remove_page_from_used_list (page_header *ph)
|
|
1298 {
|
|
1299 page_list_header *plh = PH_PLH (ph);
|
|
1300
|
|
1301 #ifdef MEMORY_USAGE_STATS
|
|
1302 PLH_TOTAL_CELLS (plh) -= PH_CELLS_ON_PAGE (ph);
|
|
1303 PLH_TOTAL_SPACE (plh) -= PAGE_SIZE * PH_N_PAGES (ph);
|
|
1304 #endif
|
|
1305
|
|
1306 /* clean up mark bits and cell free list */
|
|
1307 remove_cell_free_list (ph);
|
|
1308 if (PH_ON_USED_LIST_P (ph))
|
|
1309 remove_mark_bits (ph);
|
|
1310
|
|
1311 /* clean up page header */
|
|
1312 PH_CELL_SIZE (ph) = 0;
|
|
1313 PH_CELLS_ON_PAGE (ph) = 0;
|
|
1314 PH_CELLS_USED (ph) = 0;
|
|
1315
|
|
1316 /* remove from used list */
|
|
1317 remove_page_header_from_plh (ph, plh);
|
|
1318
|
|
1319 /* move to free list */
|
|
1320 merge_into_free_list (ph);
|
|
1321 }
|
|
1322
|
|
1323
|
|
1324
|
|
1325
|
|
1326 /*--- allocation -------------------------------------------------------*/
|
|
1327
|
|
1328 /* Allocates from cell free list on already allocated pages. */
|
|
1329 static page_header *
|
|
1330 allocate_cell (page_list_header *plh)
|
|
1331 {
|
|
1332 page_header *ph = PLH_FIRST (plh);
|
|
1333 if (ph)
|
|
1334 {
|
|
1335 if (PH_FREE_LIST (ph))
|
|
1336 /* elements free on first page */
|
|
1337 return ph;
|
|
1338 else if ((PH_NEXT (ph))
|
|
1339 && (PH_FREE_LIST (PH_NEXT (ph))))
|
|
1340 /* elements free on second page */
|
|
1341 {
|
|
1342 page_header *temp = PH_NEXT (ph);
|
|
1343 /* move full page (first page) to end of list */
|
|
1344 PH_NEXT (PLH_LAST (plh)) = ph;
|
|
1345 PH_PREV (ph) = PLH_LAST (plh);
|
|
1346 PLH_LAST (plh) = ph;
|
|
1347 PH_NEXT (ph) = 0;
|
|
1348 /* install second page as first page */
|
|
1349 ph = temp;
|
|
1350 PH_PREV (ph) = 0;
|
|
1351 PLH_FIRST (plh) = ph;
|
|
1352 return ph;
|
|
1353 }
|
|
1354 }
|
|
1355 return 0;
|
|
1356 }
|
|
1357
|
|
1358
|
|
1359 /* Finds a page which has at least the needed number of pages.
|
|
1360 Algorithm: FIRST FIT. */
|
|
1361 static page_header *
|
|
1362 find_free_page_first_fit (EMACS_INT needed_pages, page_header *ph)
|
|
1363 {
|
|
1364 while (ph)
|
|
1365 {
|
|
1366 if (PH_N_PAGES (ph) >= needed_pages)
|
|
1367 return ph;
|
|
1368 ph = PH_NEXT (ph);
|
|
1369 }
|
|
1370 return 0;
|
|
1371 }
|
|
1372
|
|
1373
|
|
1374 /* Allocates a page from the free list. */
|
|
1375 static page_header *
|
|
1376 allocate_page_from_free_list (EMACS_INT needed_pages)
|
|
1377 {
|
|
1378 page_header *ph = 0;
|
|
1379 int i;
|
|
1380 for (i = get_free_list_index (needed_pages); i < N_FREE_PAGE_LISTS; i++)
|
|
1381 if ((ph = find_free_page_first_fit (needed_pages,
|
|
1382 PLH_FIRST (FREE_HEAP_PAGES (i)))) != 0)
|
|
1383 {
|
|
1384 if (PH_N_PAGES (ph) > needed_pages)
|
|
1385 return split_page (ph, needed_pages);
|
|
1386 else
|
|
1387 {
|
|
1388 remove_page_from_free_list (ph);
|
|
1389 return ph;
|
|
1390 }
|
|
1391 }
|
|
1392 return 0;
|
|
1393 }
|
|
1394
|
|
1395
|
|
1396 /* Allocates a new page, either from free list or by expanding the heap. */
|
|
1397 static page_header *
|
|
1398 allocate_new_page (page_list_header *plh, size_t size, int managed)
|
|
1399 {
|
|
1400 EMACS_INT needed_pages = BYTES_TO_PAGES (size);
|
|
1401 /* first check free list */
|
|
1402 page_header *result = allocate_page_from_free_list (needed_pages);
|
|
1403 if (!result)
|
|
1404 /* expand heap */
|
|
1405 result = expand_heap (needed_pages);
|
|
1406 install_page_in_used_list (result, plh, size, managed);
|
|
1407 return result;
|
|
1408 }
|
|
1409
|
|
1410
|
|
1411 /* Selects the correct size class, tries to allocate a cell of this size
|
|
1412 from the free list, if this fails, a new page is allocated. */
|
|
1413 static void *
|
|
1414 mc_alloc_1 (size_t size, int managed)
|
|
1415 {
|
|
1416 page_list_header *plh = 0;
|
|
1417 if (managed)
|
|
1418 plh = USED_HEAP_PAGES (get_used_list_index (size));
|
|
1419 else
|
|
1420 plh = UNMANAGED_HEAP_PAGES (get_unmanaged_list_index (size));
|
|
1421
|
|
1422 page_header *ph = 0;
|
|
1423 void *result = 0;
|
|
1424 if (size == 0)
|
|
1425 return 0;
|
|
1426 if (size < PAGE_SIZE_DIV_2)
|
|
1427 /* first check any free cells */
|
|
1428 ph = allocate_cell (plh);
|
|
1429 if (!ph)
|
|
1430 /* allocate a new page */
|
|
1431 ph = allocate_new_page (plh, size, managed);
|
|
1432
|
|
1433 /* return first element of free list and remove it from the list */
|
|
1434 result = (void*) PH_FREE_LIST (ph);
|
|
1435 PH_FREE_LIST (ph) =
|
|
1436 NEXT_FREE (PH_FREE_LIST (ph));
|
|
1437
|
|
1438 memset (result, '\0', size);
|
|
1439 if (managed)
|
|
1440 MARK_LRECORD_AS_FREE (result);
|
|
1441
|
|
1442 /* bump used cells counter */
|
|
1443 PH_CELLS_USED (ph)++;
|
|
1444
|
|
1445 #ifdef MEMORY_USAGE_STATS
|
|
1446 PLH_USED_CELLS (plh)++;
|
|
1447 if (managed)
|
|
1448 PLH_USED_SPACE (plh) += size;
|
|
1449 else
|
|
1450 PLH_USED_SPACE (plh) += PLH_SIZE (plh);
|
|
1451 #endif
|
|
1452
|
|
1453 return result;
|
|
1454 }
|
|
1455
|
|
1456 void *
|
|
1457 mc_alloc (size_t size)
|
|
1458 {
|
|
1459 return mc_alloc_1 (size, 1);
|
|
1460 }
|
|
1461
|
|
1462 void *
|
|
1463 mc_alloc_unmanaged (size_t size)
|
|
1464 {
|
|
1465 return mc_alloc_1 (size, 0);
|
|
1466 }
|
|
1467
|
|
1468
|
|
1469
|
|
1470
|
|
1471 /*--- sweep & free & finalize-------------------------------------------*/
|
|
1472
|
|
1473 /* Frees a heap pointer. */
|
|
1474 static void
|
|
1475 remove_cell (void *ptr, page_header *ph)
|
|
1476 {
|
|
1477 #ifdef MEMORY_USAGE_STATS
|
|
1478 PLH_USED_CELLS (PH_PLH (ph))--;
|
|
1479 if (PH_ON_USED_LIST_P (ph))
|
|
1480 PLH_USED_SPACE (PH_PLH (ph)) -=
|
|
1481 detagged_lisp_object_size ((const struct lrecord_header *) ptr);
|
|
1482 else
|
|
1483 PLH_USED_SPACE (PH_PLH (ph)) -= PH_CELL_SIZE (ph);
|
|
1484 #endif
|
|
1485 #ifdef ERROR_CHECK_GC
|
|
1486 if (PH_ON_USED_LIST_P (ph)) {
|
|
1487 #ifdef MC_ALLOC_TYPE_STATS
|
|
1488 dec_lrecord_stats (PH_CELL_SIZE (ph),
|
|
1489 (const struct lrecord_header *) ptr);
|
|
1490 #endif /* MC_ALLOC_TYPE_STATS */
|
|
1491 assert (!LRECORD_FREE_P (ptr));
|
|
1492 deadbeef_memory (ptr, PH_CELL_SIZE (ph));
|
|
1493 MARK_LRECORD_AS_FREE (ptr);
|
|
1494 }
|
|
1495 #endif
|
|
1496
|
|
1497 /* hooks cell into free list */
|
|
1498 NEXT_FREE (ptr) = PH_FREE_LIST (ph);
|
|
1499 PH_FREE_LIST (ph) = FREE_LIST (ptr);
|
|
1500 /* decrease cells used */
|
|
1501 PH_CELLS_USED (ph)--;
|
|
1502 }
|
|
1503
|
|
1504
|
|
1505 /* Mark free list marks all free list entries. */
|
|
1506 static void
|
|
1507 mark_free_list (page_header *ph)
|
|
1508 {
|
|
1509 free_link *fl = PH_FREE_LIST (ph);
|
|
1510 while (fl)
|
|
1511 {
|
|
1512 SET_BIT (ph, get_mark_bit_index (fl, ph), 1);
|
|
1513 fl = NEXT_FREE (fl);
|
|
1514 }
|
|
1515 }
|
|
1516
|
|
1517 /* Finalize a page. You have to tell mc-alloc how to call your
|
|
1518 object's finalizer. Therefore, you have to define the macro
|
|
1519 MC_ALLOC_CALL_FINALIZER(ptr). This macro should do nothing else
|
|
1520 then test if there is a finalizer and call it on the given
|
|
1521 argument, which is the heap address of the object. */
|
|
1522 static void
|
|
1523 finalize_page (page_header *ph)
|
|
1524 {
|
|
1525 EMACS_INT heap_space = (EMACS_INT) PH_HEAP_SPACE (ph);
|
|
1526 EMACS_INT heap_space_step = PH_CELL_SIZE (ph);
|
|
1527 EMACS_INT mark_bit = 0;
|
|
1528 EMACS_INT mark_bit_max_index = PH_CELLS_ON_PAGE (ph);
|
|
1529 int bit = 0;
|
|
1530
|
|
1531 mark_free_list (ph);
|
|
1532
|
|
1533 for (mark_bit = 0; mark_bit < mark_bit_max_index; mark_bit++)
|
|
1534 {
|
|
1535 GET_BIT (bit, ph, mark_bit);
|
|
1536 if (!bit)
|
|
1537 {
|
|
1538 EMACS_INT ptr = (heap_space + (heap_space_step * mark_bit));
|
|
1539 MC_ALLOC_CALL_FINALIZER ((void *) ptr);
|
|
1540 }
|
|
1541 }
|
|
1542 }
|
|
1543
|
|
1544
|
|
1545 /* Finalize a page for disksave. XEmacs calls this routine before it
|
|
1546 dumps the heap image. You have to tell mc-alloc how to call your
|
|
1547 object's finalizer for disksave. Therefore, you have to define the
|
|
1548 macro MC_ALLOC_CALL_FINALIZER_FOR_DISKSAVE(ptr). This macro should
|
|
1549 do nothing else then test if there is a finalizer and call it on
|
|
1550 the given argument, which is the heap address of the object. */
|
|
1551 static void
|
|
1552 finalize_page_for_disksave (page_header *ph)
|
|
1553 {
|
|
1554 EMACS_INT heap_space = (EMACS_INT) PH_HEAP_SPACE (ph);
|
|
1555 EMACS_INT heap_space_step = PH_CELL_SIZE (ph);
|
|
1556 EMACS_INT mark_bit = 0;
|
|
1557 EMACS_INT mark_bit_max_index = PH_CELLS_ON_PAGE (ph);
|
|
1558
|
|
1559 mark_free_list (ph);
|
|
1560
|
|
1561 for (mark_bit = 0; mark_bit < mark_bit_max_index; mark_bit++)
|
|
1562 {
|
|
1563 EMACS_INT ptr = (heap_space + (heap_space_step * mark_bit));
|
|
1564 MC_ALLOC_CALL_FINALIZER_FOR_DISKSAVE ((void *) ptr);
|
|
1565 }
|
|
1566 }
|
|
1567
|
|
1568
|
|
1569 /* Finalizes the heap. */
|
|
1570 void
|
|
1571 mc_finalize (void)
|
|
1572 {
|
|
1573 visit_all_used_page_headers (finalize_page);
|
|
1574 }
|
|
1575
|
|
1576
|
|
1577 /* Finalizes the heap for disksave. */
|
|
1578 void
|
|
1579 mc_finalize_for_disksave (void)
|
|
1580 {
|
|
1581 visit_all_used_page_headers (finalize_page_for_disksave);
|
|
1582 }
|
|
1583
|
|
1584
|
|
1585 /* Sweeps a page: all the non-marked cells are freed. If the page is empty
|
|
1586 in the end, it is removed. If some cells are free, it is moved to the
|
|
1587 front of its page header list. Full pages stay where they are. */
|
|
1588 static void
|
|
1589 sweep_page (page_header *ph)
|
|
1590 {
|
|
1591 char *heap_space = (char *) PH_HEAP_SPACE (ph);
|
|
1592 EMACS_INT heap_space_step = PH_CELL_SIZE (ph);
|
|
1593 EMACS_INT mark_bit = 0;
|
|
1594 EMACS_INT mark_bit_max_index = PH_CELLS_ON_PAGE (ph);
|
|
1595 int bit = 0;
|
|
1596
|
|
1597 mark_free_list (ph);
|
|
1598
|
|
1599 for (mark_bit = 0; mark_bit < mark_bit_max_index; mark_bit++)
|
|
1600 {
|
|
1601 GET_BIT (bit, ph, mark_bit);
|
|
1602 if (!bit)
|
|
1603 {
|
|
1604 remove_cell (heap_space + (heap_space_step * mark_bit), ph);
|
|
1605 }
|
|
1606 }
|
|
1607 zero_mark_bits (ph);
|
|
1608 if (PH_CELLS_USED (ph) == 0)
|
|
1609 remove_page_from_used_list (ph);
|
|
1610 else if (PH_CELLS_USED (ph) < PH_CELLS_ON_PAGE (ph))
|
|
1611 move_page_header_to_front (ph);
|
|
1612 }
|
|
1613
|
|
1614
|
|
1615 /* Sweeps the heap. */
|
|
1616 void
|
|
1617 mc_sweep (void)
|
|
1618 {
|
|
1619 visit_all_used_page_headers (sweep_page);
|
|
1620 }
|
|
1621
|
|
1622
|
|
1623 /* Frees the cell pointed to by ptr. */
|
|
1624 void
|
|
1625 mc_free (void *ptr)
|
|
1626 {
|
|
1627 page_header *ph = get_page_header (ptr);
|
|
1628 assert (!PH_ON_FREE_LIST_P (ph));
|
|
1629
|
|
1630 remove_cell (ptr, ph);
|
|
1631
|
|
1632 if (PH_CELLS_USED (ph) == 0)
|
|
1633 remove_page_from_used_list (ph);
|
|
1634 else if (PH_CELLS_USED (ph) < PH_CELLS_ON_PAGE (ph))
|
|
1635 move_page_header_to_front (ph);
|
|
1636 }
|
|
1637
|
|
1638
|
|
1639 /* Changes the size of the cell pointed to by ptr.
|
|
1640 Returns the new address of the new cell with new size. */
|
|
1641 void *
|
|
1642 mc_realloc_1 (void *ptr, size_t size, int managed)
|
|
1643 {
|
|
1644 if (ptr)
|
|
1645 {
|
|
1646 if (size)
|
|
1647 {
|
|
1648 void *result = mc_alloc_1 (size, managed);
|
|
1649 size_t from_size = PH_CELL_SIZE (get_page_header (ptr));
|
|
1650 size_t cpy_size = size;
|
|
1651 if (size > from_size)
|
|
1652 cpy_size = from_size;
|
|
1653 memcpy (result, ptr, cpy_size);
|
|
1654 mc_free (ptr);
|
|
1655 return result;
|
|
1656 }
|
|
1657 else
|
|
1658 {
|
|
1659 mc_free (ptr);
|
|
1660 return 0;
|
|
1661 }
|
|
1662 }
|
|
1663 else
|
|
1664 return mc_alloc_1 (size, managed);
|
|
1665 }
|
|
1666
|
|
1667 void *
|
|
1668 mc_realloc (void *ptr, size_t size)
|
|
1669 {
|
|
1670 return mc_realloc_1 (ptr, size, 1);
|
|
1671 }
|
|
1672
|
|
1673 void *
|
|
1674 mc_realloc_unmanaged (void *ptr, size_t size)
|
|
1675 {
|
|
1676 return mc_realloc_1 (ptr, size, 0);
|
|
1677 }
|
|
1678
|
|
1679
|
|
1680
|
|
1681
|
|
1682 /*--- initialization ---------------------------------------------------*/
|
|
1683
|
|
1684 /* Call once at the very beginning. */
|
|
1685 void
|
|
1686 init_mc_allocator (void)
|
|
1687 {
|
|
1688 int i;
|
|
1689
|
|
1690 for (i = 0; i < N_USED_PAGE_LISTS; i++)
|
|
1691 {
|
|
1692 page_list_header *plh = USED_HEAP_PAGES (i);
|
|
1693 PLH_LIST_TYPE (plh) = USED_LIST;
|
|
1694 PLH_SIZE (plh) = get_used_list_size_value (i);
|
|
1695 PLH_FIRST (plh) = 0;
|
|
1696 PLH_LAST (plh) = 0;
|
|
1697 PLH_MARK_BIT_FREE_LIST (plh) = 0;
|
|
1698 #ifdef MEMORY_USAGE_STATS
|
|
1699 PLH_PAGE_COUNT (plh) = 0;
|
|
1700 PLH_USED_CELLS (plh) = 0;
|
|
1701 PLH_USED_SPACE (plh) = 0;
|
|
1702 PLH_TOTAL_CELLS (plh) = 0;
|
|
1703 PLH_TOTAL_SPACE (plh) = 0;
|
|
1704 #endif
|
|
1705 }
|
|
1706
|
|
1707 for (i = 0; i < N_UNMANAGED_PAGE_LISTS; i++)
|
|
1708 {
|
|
1709 page_list_header *plh = UNMANAGED_HEAP_PAGES (i);
|
|
1710 PLH_LIST_TYPE (plh) = UNMANAGED_LIST;
|
|
1711 PLH_SIZE (plh) = get_unmanaged_list_size_value (i);
|
|
1712 PLH_FIRST (plh) = 0;
|
|
1713 PLH_LAST (plh) = 0;
|
|
1714 PLH_MARK_BIT_FREE_LIST (plh) = 0;
|
|
1715 #ifdef MEMORY_USAGE_STATS
|
|
1716 PLH_PAGE_COUNT (plh) = 0;
|
|
1717 PLH_USED_CELLS (plh) = 0;
|
|
1718 PLH_USED_SPACE (plh) = 0;
|
|
1719 PLH_TOTAL_CELLS (plh) = 0;
|
|
1720 PLH_TOTAL_SPACE (plh) = 0;
|
|
1721 #endif
|
|
1722 }
|
|
1723
|
|
1724 for (i = 0; i < N_FREE_PAGE_LISTS; i++)
|
|
1725 {
|
|
1726 page_list_header *plh = FREE_HEAP_PAGES (i);
|
|
1727 PLH_LIST_TYPE (plh) = FREE_LIST;
|
|
1728 PLH_SIZE (plh) = get_free_list_size_value (i);
|
|
1729 PLH_FIRST (plh) = 0;
|
|
1730 PLH_LAST (plh) = 0;
|
|
1731 PLH_MARK_BIT_FREE_LIST (plh) = 0;
|
|
1732 #ifdef MEMORY_USAGE_STATS
|
|
1733 PLH_PAGE_COUNT (plh) = 0;
|
|
1734 PLH_USED_CELLS (plh) = 0;
|
|
1735 PLH_USED_SPACE (plh) = 0;
|
|
1736 PLH_TOTAL_CELLS (plh) = 0;
|
|
1737 PLH_TOTAL_SPACE (plh) = 0;
|
|
1738 #endif
|
|
1739 }
|
|
1740
|
|
1741 PAGE_HEADER_FREE_LIST = 0;
|
|
1742
|
|
1743 #ifdef MEMORY_USAGE_STATS
|
|
1744 MC_MALLOCED_BYTES = sizeof (mc_allocator_globals);
|
|
1745 #endif
|
|
1746
|
|
1747 init_lookup_table ();
|
|
1748 }
|
|
1749
|
|
1750
|
|
1751
|
|
1752
|
|
1753 /*--- lisp function for statistics -------------------------------------*/
|
|
1754
|
|
1755 #ifdef MEMORY_USAGE_STATS
|
|
1756 DEFUN ("mc-alloc-memory-usage", Fmc_alloc_memory_usage, 0, 0, 0, /*
|
|
1757 Returns stats about the mc-alloc memory usage. See diagnose.el.
|
|
1758 */
|
|
1759 ())
|
|
1760 {
|
|
1761 Lisp_Object free_plhs = Qnil;
|
|
1762 Lisp_Object used_plhs = Qnil;
|
|
1763 Lisp_Object unmanaged_plhs = Qnil;
|
|
1764 Lisp_Object heap_sects = Qnil;
|
|
1765 int used_size = 0;
|
|
1766 int real_size = 0;
|
|
1767
|
|
1768 int i;
|
|
1769
|
|
1770 for (i = 0; i < N_FREE_PAGE_LISTS; i++)
|
|
1771 if (PLH_PAGE_COUNT (FREE_HEAP_PAGES(i)) > 0)
|
|
1772 free_plhs =
|
|
1773 acons (make_int (PLH_SIZE (FREE_HEAP_PAGES(i))),
|
|
1774 list1 (make_int (PLH_PAGE_COUNT (FREE_HEAP_PAGES(i)))),
|
|
1775 free_plhs);
|
|
1776
|
|
1777 for (i = 0; i < N_UNMANAGED_PAGE_LISTS; i++)
|
|
1778 if (PLH_PAGE_COUNT (UNMANAGED_HEAP_PAGES(i)) > 0)
|
|
1779 unmanaged_plhs =
|
|
1780 acons (make_int (PLH_SIZE (UNMANAGED_HEAP_PAGES(i))),
|
|
1781 list5 (make_int (PLH_PAGE_COUNT (UNMANAGED_HEAP_PAGES(i))),
|
|
1782 make_int (PLH_USED_CELLS (UNMANAGED_HEAP_PAGES(i))),
|
|
1783 make_int (PLH_USED_SPACE (UNMANAGED_HEAP_PAGES(i))),
|
|
1784 make_int (PLH_TOTAL_CELLS (UNMANAGED_HEAP_PAGES(i))),
|
|
1785 make_int (PLH_TOTAL_SPACE (UNMANAGED_HEAP_PAGES(i)))),
|
|
1786 unmanaged_plhs);
|
|
1787
|
|
1788 for (i = 0; i < N_USED_PAGE_LISTS; i++)
|
|
1789 if (PLH_PAGE_COUNT (USED_HEAP_PAGES(i)) > 0)
|
|
1790 used_plhs =
|
|
1791 acons (make_int (PLH_SIZE (USED_HEAP_PAGES(i))),
|
|
1792 list5 (make_int (PLH_PAGE_COUNT (USED_HEAP_PAGES(i))),
|
|
1793 make_int (PLH_USED_CELLS (USED_HEAP_PAGES(i))),
|
|
1794 make_int (PLH_USED_SPACE (USED_HEAP_PAGES(i))),
|
|
1795 make_int (PLH_TOTAL_CELLS (USED_HEAP_PAGES(i))),
|
|
1796 make_int (PLH_TOTAL_SPACE (USED_HEAP_PAGES(i)))),
|
|
1797 used_plhs);
|
|
1798
|
|
1799 for (i = 0; i < N_HEAP_SECTIONS; i++) {
|
|
1800 used_size += HEAP_SECTION(i).n_pages * PAGE_SIZE;
|
|
1801 real_size +=
|
|
1802 malloced_storage_size (0, HEAP_SECTION(i).real_size, 0);
|
|
1803 }
|
|
1804
|
|
1805 heap_sects =
|
|
1806 list3 (make_int (N_HEAP_SECTIONS),
|
|
1807 make_int (used_size),
|
|
1808 make_int (real_size));
|
|
1809
|
|
1810 return Fcons (make_int (PAGE_SIZE),
|
|
1811 list6 (heap_sects,
|
|
1812 Fnreverse (used_plhs),
|
|
1813 Fnreverse (unmanaged_plhs),
|
|
1814 Fnreverse (free_plhs),
|
|
1815 make_int (sizeof (mc_allocator_globals)),
|
|
1816 make_int (MC_MALLOCED_BYTES)));
|
|
1817 }
|
|
1818 #endif /* MEMORY_USAGE_STATS */
|
|
1819
|
|
1820 void
|
|
1821 syms_of_mc_alloc (void)
|
|
1822 {
|
|
1823 #ifdef MEMORY_USAGE_STATS
|
|
1824 DEFSUBR (Fmc_alloc_memory_usage);
|
|
1825 #endif /* MEMORY_USAGE_STATS */
|
|
1826 }
|