Fix two problems in mark & sweep GC.
[sbcl.git] / src / runtime / marknsweepgc.c
bloba62d8fd4b17daa3c77830b1b182d39cd287da9ed
1 /*
2 * Extension to GENCGC which provides for pages of objects
3 * that are static in placement but subject to reclamation.
4 */
6 /*
7 * This software is part of the SBCL system. See the README file for
8 * more information.
10 * This software is derived from the CMU CL system, which was
11 * written at Carnegie Mellon University and released into the
12 * public domain. The software is in the public domain and is
13 * provided with absolutely no warranty. See the COPYING and CREDITS
14 * files for more information.
18 * TODO:
19 * 1. Space accounting (GET-BYTES-CONSED etc)
20 * 2. Heuristic for auto-trigger. (Can't yet because no space accounting)
21 * Currently happens with regular GC trigger mechanism.
22 * 3. Specify space size on startup
25 // Work around a bug in some llvm/clang versions affecting the memcpy
26 // call in defrag_immobile_space:
28 // When compiled with _FORTIFY_SOURCE nonzero, as seems to be the
29 // default, memcpy is a macro that expands to
30 // __builtin_memcpy_chk(dst, source, size, __builtin_object_size(...)).
32 // Now usually if the compiler knows that it does not know
33 // __builtin_object_size for the source of the copy, the
34 // __builtin_memcpy_chk call becomes plain old memcpy. But in the
35 // buggy case, the compiler is convinced that it does know the
36 // size. This shows up clearly in the disassembly, where the library
37 // routine receives a source size that was erroneously determined to
38 // be a compile-time constant 0. Thus the assertion failure is that
39 // you are reading from a range with 0 bytes in it.
41 // Defining _FORTIFY_LEVEL 0 disables the above macro and thus works
42 // around the problem. Since it is unclear which clang versions are
43 // affected, only apply the workaround for the known-bad version.
44 #if (defined(__clang__) && (__clang_major__ == 6) && (__clang_minor__ == 0))
45 #define _FORTIFY_SOURCE 0
46 #endif
48 #include "gc.h"
49 #include "gc-internal.h"
50 #include "genesis/vector.h"
52 #include <stdlib.h>
53 #include <stdio.h>
55 #define FIRST_VARYOBJ_PAGE (IMMOBILE_FIXEDOBJ_SUBSPACE_SIZE/(int)IMMOBILE_CARD_BYTES)
56 #define WORDS_PER_PAGE ((int)IMMOBILE_CARD_BYTES/N_WORD_BYTES)
57 #define DOUBLEWORDS_PER_PAGE (WORDS_PER_PAGE/2)
59 #undef DEBUG
60 #undef VERIFY_PAGE_GENS
62 #ifdef DEBUG
63 # define dprintf(arg) fprintf arg
64 FILE * logfile;
65 #else
66 # define dprintf(arg)
67 #endif
69 low_page_index_t max_used_fixedobj_page, max_used_varyobj_page;
71 // This table is for objects fixed in size, as opposed to variable-sized.
72 // (Immobile objects are naturally fixed in placement)
73 struct fixedobj_page { // 12 bytes per page
74 union immobile_page_attr {
75 int packed;
76 struct {
77 unsigned char flags;
78 /* space per object in Lisp words. Can exceed obj_size
79 to align on a larger boundary */
80 unsigned char obj_align;
81 unsigned char obj_size; /* in Lisp words, incl. header */
82 /* Which generations have data on this page */
83 unsigned char gens_; // a bitmap
84 } parts;
85 } attr;
86 int free_index; // index is in bytes. 4 bytes
87 short int prior_gc_free_word_index; // index is in words. 2 bytes
88 /* page index of next page with same attributes */
89 short int page_link; // 2 bytes
90 } *fixedobj_pages;
92 unsigned int* immobile_scav_queue;
93 int immobile_scav_queue_head;
94 // Number of items enqueued; can exceed QCAPACITY on overflow.
95 // If overflowed, the queue is unusable until reset.
96 unsigned int immobile_scav_queue_count;
97 #define QCAPACITY (IMMOBILE_CARD_BYTES/sizeof(int))
99 #define gens attr.parts.gens_
101 // These are the high 2 bits of 'flags'
102 #define WRITE_PROTECT 0x80
103 #define WRITE_PROTECT_CLEARED 0x40
105 // Packing and unpacking attributes
106 // the low two flag bits are for write-protect status
107 #define MAKE_ATTR(spacing,size,flags) (((spacing)<<8)|((size)<<16)|flags)
108 #define OBJ_SPACING(attr) ((attr>>8) & 0xFF)
110 // Ignore the write-protect bits and the generations when comparing attributes
111 #define ATTRIBUTES_MATCH_P(page_attr,specified_attr) \
112 ((page_attr & 0xFFFF3F) == specified_attr)
113 #define SET_WP_FLAG(index,flag) \
114 fixedobj_pages[index].attr.parts.flags = (fixedobj_pages[index].attr.parts.flags & 0x3F) | flag
116 #define page_obj_align(i) fixedobj_pages[i].attr.parts.obj_align
117 #define page_obj_size(i) fixedobj_pages[i].attr.parts.obj_size
118 #define set_page_full(i) fixedobj_pages[i].free_index = IMMOBILE_CARD_BYTES
119 #define page_full_p(i) (fixedobj_pages[i].free_index >= (int)IMMOBILE_CARD_BYTES)
120 #define fixedobj_page_wp(i) (fixedobj_pages[i].attr.parts.flags & WRITE_PROTECT)
122 /// Variable-length pages:
124 // Array of inverted write-protect flags, 1 bit per page.
125 unsigned int* varyobj_page_touched_bits;
126 static int n_bitmap_elts; // length of array measured in 'int's
128 // Array of offsets backwards in double-lispwords from the page end
129 // to the lowest-addressed object touching the page. This offset can
130 // point to a hole, but we prefer that it not. If the offset is zero,
131 // the page has no object other than possibly a hole resulting
132 // from a freed object.
133 unsigned short* varyobj_page_scan_start_offset;
135 // Array of page generation masks
136 unsigned char* varyobj_page_header_gens;
137 // Holes to be stuffed back into the managed free list.
138 lispobj varyobj_holes;
140 #define VARYOBJ_PAGE_GENS(x) varyobj_page_header_gens[x-FIRST_VARYOBJ_PAGE]
141 #define varyobj_page_touched(x) \
142 ((varyobj_page_touched_bits[(x-FIRST_VARYOBJ_PAGE)/32] >> (x&31)) & 1)
144 #ifdef VERIFY_PAGE_GENS
145 void check_fixedobj_page(low_page_index_t);
146 void check_varyobj_pages();
147 #endif
149 // Object header: generation byte --| |-- widetag
150 // v v
151 // 0xzzzzzzzz GGzzzzww
152 // arbitrary data -------- ---- length in words
154 // There is a hard constraint on NUM_GENERATIONS, which is currently 8.
155 // (0..5=normal, 6=pseudostatic, 7=scratch)
156 // It could be as high as 16 for 32-bit words (wherein scratch=gen15)
157 // or 32 for 64-bits words (wherein scratch=gen31).
158 // In each case, the VISITED flag bit weight would need to be modified.
159 // Shifting a 1 bit left by the contents of the generation byte
160 // must not overflow a register.
162 #ifdef LISP_FEATURE_LITTLE_ENDIAN
163 static inline void assign_generation(lispobj* obj, generation_index_t gen)
165 ((generation_index_t*)obj)[3] = gen;
167 // Turn a grey node black.
168 static inline void set_visited(lispobj* obj)
170 #ifdef DEBUG
171 gc_assert(__immobile_obj_gen_bits(obj) == new_space);
172 #endif
173 ((generation_index_t*)obj)[3] |= IMMOBILE_OBJ_VISITED_FLAG;
175 #else
176 #error "Need to define assign_generation() for big-endian"
177 #endif
179 static inline void *
180 low_page_address(low_page_index_t page_num)
182 return ((void*)IMMOBILE_SPACE_START + (page_num * IMMOBILE_CARD_BYTES));
185 //// Variable-length utilities
187 /* Calculate the address where the first object touching this page starts. */
188 static inline lispobj*
189 varyobj_scan_start(low_page_index_t page_index)
191 return (lispobj*)((char*)low_page_address(page_index+1)
192 - varyobj_page_scan_start_offset[page_index - FIRST_VARYOBJ_PAGE]
193 * (2 * N_WORD_BYTES));
196 /* Return the generation mask for objects headers on 'page_index'
197 including at most one object that starts before the page but ends on
198 or after it.
199 If the scan start is within the page, i.e. less than DOUBLEWORDS_PER_PAGE
200 (note that the scan start is measured relative to the page end) then
201 we don't need to OR in the generation byte from an extra object,
202 as all headers on the page are accounted for in the page generation mask.
203 Also an empty page (where scan start is zero) avoids looking
204 at the next page's first object by accident via the same test. */
205 unsigned char varyobj_page_gens_augmented(low_page_index_t page_index)
207 return (varyobj_page_scan_start_offset[page_index - FIRST_VARYOBJ_PAGE] <= DOUBLEWORDS_PER_PAGE
208 ? 0 : (1<<__immobile_obj_generation(varyobj_scan_start(page_index))))
209 | VARYOBJ_PAGE_GENS(page_index);
212 //// Fixed-length object allocator
214 /* Return the index of an immobile page that is probably not totally full,
215 starting with 'hint_page' and wrapping around.
216 'attributes' determine an eligible page.
217 *IMMOBILE-SPACE-FREE-POINTER* is updated to point beyond the found page
218 if it previously did not. */
220 static int get_freeish_page(int hint_page, int attributes)
222 int page = hint_page;
223 lispobj new_free_pointer, old_free_pointer, actual_old;
224 struct symbol * free_pointer_sym;
225 int page_attr_packed;
226 unsigned char best_genmask = 0xff;
227 int best_page = -1;
229 // Speed of this could be improved by keeping a linked list of pages
230 // with any space available, headed by a field in the page struct.
231 // This is totally lock-free / wait-free though, so it's really not
232 // too shabby, because it never has to deal with a page-table mutex.
233 do {
234 page_attr_packed = fixedobj_pages[page].attr.packed;
235 if (page_attr_packed == 0)
236 if ((page_attr_packed =
237 __sync_val_compare_and_swap(&fixedobj_pages[page].attr.packed,
238 0, attributes)) == 0) {
239 // Atomically assign MAX(old_free_pointer, new_free_pointer)
240 // into the free pointer.
241 free_pointer_sym = SYMBOL(IMMOBILE_FIXEDOBJ_FREE_POINTER);
242 new_free_pointer = (lispobj)low_page_address(page+1);
243 old_free_pointer = free_pointer_sym->value;
244 while (new_free_pointer > old_free_pointer) {
245 actual_old =
246 __sync_val_compare_and_swap(&free_pointer_sym->value,
247 old_free_pointer,
248 new_free_pointer);
249 if (actual_old == old_free_pointer)
250 break;
251 old_free_pointer = actual_old;
253 return page;
255 if (ATTRIBUTES_MATCH_P(page_attr_packed, attributes)
256 && !page_full_p(page)) {
257 if (fixedobj_pages[page].gens <= 1) { // instant win
258 return page;
259 } else if (fixedobj_pages[page].gens < best_genmask) {
260 best_genmask = fixedobj_pages[page].gens;
261 best_page = page;
264 if (++page >= FIRST_VARYOBJ_PAGE) page = 0;
265 } while (page != hint_page);
266 if (best_page >= 0)
267 return best_page;
268 lose("No more immobile pages available");
271 // Unused, but possibly will be for some kind of collision-avoidance scheme
272 // on claiming of new free pages.
273 long immobile_alloc_collisions;
275 /* Beginning at page index *hint, attempt to find space
276 for an object on a page with page_attributes. Write its header word
277 and return a C (native) pointer. The start page MUST have the proper
278 characteristisc, but might be totally full.
280 Precondition: Lisp has established a pseudo-atomic section. */
282 /* There is a slightly different algorithm that would probably be faster
283 than what is currently implemented:
284 - hint should be the address of a word that you try to claim
285 as an object header; it moves from high-to-low instead of low-to-high.
286 It's easier to compute the page base than the last valid object start
287 if there are some wasted words at the end due to page size not being
288 a perfect multiple of object size.
289 - you do a CAS into that word, and either suceed or fail
290 - if you succeed, subtract the object spacing and compare
291 to the page's base address, which can be computed by
292 masking. if the next address is above or equal to the page start,
293 store it in the hint, otherwise mark the page full */
295 lispobj alloc_immobile_obj(int page_attributes, lispobj header, int* hint)
297 int page;
298 lispobj word;
299 char * page_data, * obj_ptr, * next_obj_ptr, * limit, * next_free;
300 int spacing_in_bytes = OBJ_SPACING(page_attributes) << WORD_SHIFT;
302 page = *hint;
303 #ifdef DEBUG
304 gc_assert(low_page_address(page) < (void*)SYMBOL(IMMOBILE_FIXEDOBJ_FREE_POINTER)->value);
305 #endif
306 do {
307 page_data = low_page_address(page);
308 obj_ptr = page_data + fixedobj_pages[page].free_index;
309 limit = page_data + IMMOBILE_CARD_BYTES - spacing_in_bytes;
310 while (obj_ptr <= limit) {
311 word = *(lispobj*)obj_ptr;
312 next_obj_ptr = obj_ptr + spacing_in_bytes;
313 if (fixnump(word) // a fixnum marks free space
314 && __sync_bool_compare_and_swap((lispobj*)obj_ptr,
315 word, header)) {
316 // The value formerly in the header word was the offset to
317 // the next hole. Use it to update the freelist pointer.
318 // Just slam it in.
319 fixedobj_pages[page].free_index = next_obj_ptr + word - page_data;
320 return (lispobj)obj_ptr;
322 // If some other thread updated the free_index
323 // to a larger value, use that. (See example below)
324 next_free = page_data + fixedobj_pages[page].free_index;
325 obj_ptr = next_free > next_obj_ptr ? next_free : next_obj_ptr;
327 set_page_full(page);
328 page = get_freeish_page(page+1 >= FIRST_VARYOBJ_PAGE ? 0 : page+1,
329 page_attributes);
330 *hint = page;
331 } while (1);
335 Example: Conside the freelist initially pointing to word index 6
336 Threads A, and B, and C each want to claim index 6.
337 - Thread A wins and then is switched out immediately after the CAS.
338 - Thread B fails to claim cell 6, claims cell 12 instead.
339 - Thread C fails to claim a cell and is switched out immediately
340 after the CAS.
341 - Thread B writes the index of the next hole, cell 18 into the
342 page's freelist cell.
343 - Thread A wakes up and writes 12 into the freelist cell.
344 - Thread C wakes up sees 12 for next_offset. 12 is greater than 6,
345 so it sets its next probe location to 12.
346 It fails the fixnump(header) test.
347 - Thread C sees that next_offset is still 12,
348 so it skips by the page's object spacing instead, and will continue
349 to do so until hitting the end of the page.
352 //// The collector
354 void update_immobile_nursery_bits()
356 low_page_index_t page;
357 lispobj fixedobj_free_ptr = SYMBOL(IMMOBILE_FIXEDOBJ_FREE_POINTER)->value;
358 lispobj varyobj_free_ptr = SYMBOL(IMMOBILE_SPACE_FREE_POINTER)->value;
360 // Find the high water marks for this GC scavenge phase
361 // [avoid passing exactly IMMOBILE_SPACE_END, which has no page index]
362 max_used_fixedobj_page = find_immobile_page_index((void*)(fixedobj_free_ptr-1));
363 max_used_varyobj_page = find_immobile_page_index((void*)(varyobj_free_ptr-1));
365 immobile_scav_queue = (unsigned int*)low_page_address(max_used_varyobj_page+1);
366 gc_assert((IMMOBILE_SPACE_END - (uword_t)immobile_scav_queue) / sizeof(int)
367 >= QCAPACITY);
369 // Unprotect the in-use ranges. Any page could be written during scavenge
370 os_protect((os_vm_address_t)IMMOBILE_SPACE_START,
371 fixedobj_free_ptr - IMMOBILE_SPACE_START,
372 OS_VM_PROT_ALL);
374 // varyobj_free_ptr is typically not page-aligned - only by random chance
375 // might it be. Additionally we need a page beyond that for the re-scan queue.
376 os_vm_address_t limit = (char*)immobile_scav_queue + IMMOBILE_CARD_BYTES;
377 os_protect((os_vm_address_t)(IMMOBILE_VARYOBJ_SUBSPACE_START),
378 limit - (os_vm_address_t)IMMOBILE_VARYOBJ_SUBSPACE_START,
379 OS_VM_PROT_ALL);
381 for (page=0; page <= max_used_fixedobj_page ; ++page) {
382 // any page whose free index changed contains nursery objects
383 if (fixedobj_pages[page].free_index >> WORD_SHIFT !=
384 fixedobj_pages[page].prior_gc_free_word_index)
385 fixedobj_pages[page].gens |= 1;
386 #ifdef VERIFY_PAGE_GENS
387 check_fixedobj_page(page);
388 #endif
390 #ifdef VERIFY_PAGE_GENS
391 check_varyobj_pages();
392 #endif
395 #ifdef SIMPLE_CHARACTER_STRING_WIDETAG
396 #define MAXIMUM_STRING_WIDETAG SIMPLE_CHARACTER_STRING_WIDETAG
397 #else
398 #define MAXIMUM_STRING_WIDETAG SIMPLE_BASE_STRING_WIDETAG
399 #endif
401 static inline boolean unboxed_array_p(int widetag)
403 // This is not an exhaustive test for unboxed objects,
404 // but it's enough to avoid some unnecessary scavenging.
405 return (widetag >= SIMPLE_ARRAY_UNSIGNED_BYTE_2_WIDETAG
406 && widetag <= MAXIMUM_STRING_WIDETAG
407 && widetag != SIMPLE_VECTOR_WIDETAG);
410 /* Turn a white object grey. Also enqueue the object for re-scan if required */
411 void
412 promote_immobile_obj(lispobj *ptr, int rescan) // a native pointer
414 if (widetag_of(*ptr) == SIMPLE_FUN_HEADER_WIDETAG)
415 ptr = (lispobj*)code_obj_from_simple_fun((struct simple_fun*)ptr);
416 gc_assert(__immobile_obj_gen_bits(ptr) == from_space);
417 int pointerish = !unboxed_array_p(widetag_of(*ptr));
418 assign_generation(ptr, (pointerish ? 0 : IMMOBILE_OBJ_VISITED_FLAG) | new_space);
419 low_page_index_t page_index = find_immobile_page_index(ptr);
421 if (page_index >= FIRST_VARYOBJ_PAGE) {
422 VARYOBJ_PAGE_GENS(page_index) |= 1<<new_space;
423 } else {
424 fixedobj_pages[page_index].gens |= 1<<new_space;
426 // If called from preserve_pointer(), then we haven't scanned immobile
427 // roots yet, so we only need ensure that this object's page's WP bit
428 // is cleared so that the page is not skipped during root scan.
429 if (!rescan) {
430 if (pointerish) {
431 if (page_index >= FIRST_VARYOBJ_PAGE)
432 varyobj_page_touched_bits[(page_index-FIRST_VARYOBJ_PAGE)/32]
433 |= 1 << (page_index & 31);
434 else
435 SET_WP_FLAG(page_index, WRITE_PROTECT_CLEARED);
437 return; // No need to enqueue.
440 // Do nothing if either we don't need to look for pointers in this object,
441 // or the work queue has already overflowed, causing a full scan.
442 if (!pointerish || immobile_scav_queue_count > QCAPACITY) return;
444 // count is either less than or equal to QCAPACITY.
445 // If equal, just bump the count to signify overflow.
446 if (immobile_scav_queue_count < QCAPACITY) {
447 immobile_scav_queue[immobile_scav_queue_head] =
448 (uword_t)ptr & 0xFFFFFFFF; // Drop the high bits
449 immobile_scav_queue_head = (immobile_scav_queue_head + 1) & (QCAPACITY - 1);
451 ++immobile_scav_queue_count;
454 /* If 'addr' points to an immobile object, then make the object
455 live by promotion. But if the object is not in the generation
456 being collected, do nothing */
457 void immobile_space_preserve_pointer(void* addr)
459 low_page_index_t page_index = find_immobile_page_index(addr);
460 if (page_index < 0)
461 return;
463 lispobj* header_addr;
464 if (page_index >= FIRST_VARYOBJ_PAGE) {
465 // Restrict addr to lie below IMMOBILE_SPACE_FREE_POINTER.
466 // This way, if the gens byte is nonzero but there is
467 // a final array acting as filler on the remainder of the
468 // final page, we won't accidentally find that.
469 lispobj* start;
470 if ((lispobj)addr >= SYMBOL(IMMOBILE_SPACE_FREE_POINTER)->value
471 || !(varyobj_page_gens_augmented(page_index) & (1<<from_space))
472 || (start = varyobj_scan_start(page_index)) > (lispobj*)addr)
473 return;
474 header_addr = gc_search_space(start,
475 native_pointer((lispobj)addr)+2 - start,
476 (lispobj*)addr);
477 if (!header_addr || immobile_filler_p(header_addr))
478 return;
479 gc_assert(other_immediate_lowtag_p(*header_addr));
480 // FIXME: instruction pointers aren't tagged,
481 // but this should be less conservative for everything else.
482 //if (!properly_tagged_descriptor_p((lispobj)addr, header_addr))
483 // return;
484 } else if (fixedobj_pages[page_index].gens & (1<<from_space)) {
485 int obj_spacing = (page_obj_align(page_index) << WORD_SHIFT);
486 int obj_index = ((uword_t)addr & (IMMOBILE_CARD_BYTES-1)) / obj_spacing;
487 dprintf((logfile,"Pointer %p is to immobile page %d, object %d\n",
488 addr, page_index, obj_index));
489 char* page_start_addr = (char*)((uword_t)addr & ~(IMMOBILE_CARD_BYTES-1));
490 header_addr = (lispobj*)(page_start_addr + obj_index * obj_spacing);
491 if (fixnump(*header_addr) ||
492 (lispobj*)addr >= header_addr + page_obj_size(page_index) ||
493 !properly_tagged_descriptor_p((lispobj)addr, header_addr))
494 return;
495 } else {
496 return;
498 if (__immobile_obj_gen_bits(header_addr) == from_space) {
499 dprintf((logfile,"immobile obj @ %p (<- %p) is conservatively live\n",
500 header_addr, addr));
501 promote_immobile_obj(header_addr, 0);
505 // Loop over the newly-live objects, scavenging them for pointers.
506 // As with the ordinary gencgc algorithm, this uses almost no stack.
507 static void full_scavenge_immobile_newspace()
509 page_index_t page;
510 unsigned char bit = 1<<new_space;
512 // Fixed-size object pages.
514 for (page = 0; page <= max_used_fixedobj_page; ++page) {
515 if (!(fixedobj_pages[page].gens & bit)) continue;
516 // Skip amount within the loop is in bytes.
517 int obj_spacing = page_obj_align(page) << WORD_SHIFT;
518 int n_words = page_obj_size(page);
519 lispobj* obj = low_page_address(page);
520 lispobj* limit = (lispobj*)((char*)obj +
521 IMMOBILE_CARD_BYTES - obj_spacing);
522 for ( ; obj <= limit ; obj = (lispobj*)((char*)obj + obj_spacing) ) {
523 if (!fixnump(*obj) && __immobile_obj_gen_bits(obj) == new_space) {
524 set_visited(obj);
525 scavenge(obj, n_words);
530 // Variable-size object pages
532 page = FIRST_VARYOBJ_PAGE - 1; // Subtract 1 because of pre-increment
533 while (1) {
534 // Find the next page with anything in newspace.
535 do {
536 if (++page > max_used_varyobj_page) return;
537 } while ((VARYOBJ_PAGE_GENS(page) & bit) == 0);
538 lispobj* obj = varyobj_scan_start(page);
539 do {
540 lispobj* limit = (lispobj*)low_page_address(page) + WORDS_PER_PAGE;
541 int widetag, n_words;
542 for ( ; obj < limit ; obj += n_words ) {
543 n_words = sizetab[widetag = widetag_of(*obj)](obj);
544 if (__immobile_obj_gen_bits(obj) == new_space) {
545 set_visited(obj);
546 scavenge(obj, n_words);
549 page = find_immobile_page_index(obj);
550 // Bail out if exact absolute end of immobile space was reached.
551 if (page < 0) return;
552 // If 'page' should be scanned, then pick up where we left off,
553 // without recomputing 'obj' but setting a higher 'limit'.
554 } while (VARYOBJ_PAGE_GENS(page) & bit);
558 /// Repeatedly scavenge immobile newspace work queue until we find no more
559 /// reachable objects within. (They might be in dynamic space though).
560 /// If queue overflow already happened, then a worst-case full scan is needed.
561 /// If it didn't, we try to drain the queue, hoping that overflow does
562 /// not happen while doing so.
563 /// The approach taken is more subtle than just dequeuing each item,
564 /// scavenging, and letting the outer 'while' loop take over.
565 /// That would be ok, but could cause more full scans than necessary.
566 /// Instead, since each entry in the queue is useful information
567 /// in the non-overflow condition, perform all the work indicated thereby,
568 /// rather than considering the queue discardable as soon as overflow happens.
569 /// Essentially we just have to capture the valid span of enqueued items,
570 /// because the queue state is inconsistent when 'count' exceeds 'capacity'.
571 void scavenge_immobile_newspace()
573 while (immobile_scav_queue_count) {
574 if (immobile_scav_queue_count > QCAPACITY) {
575 immobile_scav_queue_count = 0;
576 full_scavenge_immobile_newspace();
577 } else {
578 int queue_index_from = (immobile_scav_queue_head - immobile_scav_queue_count)
579 & (QCAPACITY - 1);
580 int queue_index_to = immobile_scav_queue_head;
581 int i = queue_index_from;
582 // The termination condition can't be expressed as an inequality,
583 // since the indices might be reversed due to wraparound.
584 // To express as equality entails forcing at least one iteration
585 // since the ending index might be the starting index.
586 do {
587 lispobj* obj = (lispobj*)(uword_t)immobile_scav_queue[i];
588 i = (1 + i) & (QCAPACITY-1);
589 // Only decrement the count if overflow did not happen.
590 // The first iteration of this loop will decrement for sure,
591 // but subsequent iterations might not.
592 if (immobile_scav_queue_count <= QCAPACITY)
593 --immobile_scav_queue_count;
594 if (!(__immobile_obj_gen_bits(obj) & IMMOBILE_OBJ_VISITED_FLAG)) {
595 set_visited(obj);
596 scavenge(obj, sizetab[widetag_of(*obj)](obj));
598 } while (i != queue_index_to);
603 // Return a page >= page_index having potential old->young pointers,
604 // or -1 if there isn't one.
605 static int next_varyobj_root_page(unsigned int page_index,
606 unsigned int end_bitmap_index,
607 unsigned char genmask)
609 unsigned int map_index = (page_index - FIRST_VARYOBJ_PAGE) / 32;
610 if (map_index >= end_bitmap_index) return -1;
611 int bit_index = page_index & 31;
612 // Look only at bits of equal or greater weight than bit_index.
613 unsigned int word = (0xFFFFFFFFU << bit_index) & varyobj_page_touched_bits[map_index];
614 while (1) {
615 if (word) {
616 bit_index = ffs(word) - 1;
617 page_index = FIRST_VARYOBJ_PAGE + map_index * 32 + bit_index;
618 if (varyobj_page_gens_augmented(page_index) & genmask)
619 return page_index;
620 else {
621 word ^= (1<<bit_index);
622 continue;
625 if (++map_index >= end_bitmap_index) return -1;
626 word = varyobj_page_touched_bits[map_index];
630 void
631 scavenge_immobile_roots(generation_index_t min_gen, generation_index_t max_gen)
633 // example: scavenging gens 2..6, the mask of root gens is #b1111100
634 int genmask = ((1 << (max_gen - min_gen + 1)) - 1) << min_gen;
636 low_page_index_t page;
637 for (page = 0; page <= max_used_fixedobj_page ; ++page) {
638 if (fixedobj_page_wp(page) || !(fixedobj_pages[page].gens & genmask))
639 continue;
640 int obj_spacing = page_obj_align(page) << WORD_SHIFT;
641 int n_words = page_obj_size(page);
642 lispobj* obj = low_page_address(page);
643 lispobj* limit = (lispobj*)((char*)obj +
644 IMMOBILE_CARD_BYTES - obj_spacing);
645 int gen;
646 // Immobile space can only contain objects with a header word,
647 // no conses, so any fixnum where a header could be is not a live
648 // object.
649 do {
650 if (!fixnump(*obj) && (genmask >> (gen=__immobile_obj_gen_bits(obj)) & 1)) {
651 if (gen == new_space) { set_visited(obj); }
652 scavenge(obj, n_words);
654 } while ((obj = (lispobj*)((char*)obj + obj_spacing)) <= limit);
657 // Variable-length object pages
658 unsigned n_varyobj_pages = 1+max_used_varyobj_page-FIRST_VARYOBJ_PAGE;
659 unsigned end_bitmap_index = (n_varyobj_pages+31)/32;
660 page = next_varyobj_root_page(FIRST_VARYOBJ_PAGE, end_bitmap_index, genmask);
661 while (page >= 0) {
662 lispobj* obj = varyobj_scan_start(page);
663 do {
664 lispobj* limit = (lispobj*)low_page_address(page) + WORDS_PER_PAGE;
665 int widetag, n_words, gen;
666 for ( ; obj < limit ; obj += n_words ) {
667 n_words = sizetab[widetag = widetag_of(*obj)](obj);
668 if (genmask >> (gen=__immobile_obj_gen_bits(obj)) & 1) {
669 if (gen == new_space) { set_visited(obj); }
670 scavenge(obj, n_words);
673 page = find_immobile_page_index(obj);
674 } while (page > 0
675 && (VARYOBJ_PAGE_GENS(page) & genmask)
676 && varyobj_page_touched(page));
677 page = next_varyobj_root_page(1+page, end_bitmap_index, genmask);
679 scavenge_immobile_newspace();
682 #include "genesis/layout.h"
683 #define LAYOUT_SIZE (sizeof (struct layout)/N_WORD_BYTES)
685 // As long as Lisp doesn't have any native allocators (vops and whatnot)
686 // it doesn't need to access these values.
687 int layout_page_hint, symbol_page_hint, fdefn_page_hint;
689 // For the three different page characteristics that we need,
690 // claim a page that works for those characteristics.
691 void set_immobile_space_hints()
693 // The allocator doesn't check whether each 'hint' points to an
694 // expected kind of page, so we have to ensure up front that
695 // allocations start on different pages. i.e. You can point to
696 // a totally full page, but you can't point to a wrong page.
697 // It doesn't work to just assign these to consecutive integers
698 // without also updating the page attributes.
700 // Object sizes must be multiples of 2 because the n_words value we pass
701 // to scavenge() is gotten from the page attributes, and scavenge asserts
702 // that the ending address is aligned to a doubleword boundary as expected.
704 // LAYOUTs are 256-byte-aligned so that the low byte contains no information.
705 // This makes it possible to recover a layout pointer from an instance header
706 // by simply changing the low byte to instance-pointer-lowtag.
707 // As a test of objects using larger-than-required alignment,
708 // the 64-bit implementation uses 256-byte alignment for layouts,
709 // even though the header can store all bits of the layout pointer.
710 // The 32-bit implementation would also need somewhere different to store
711 // the generation byte of each layout, which is a minor annoyance.
712 layout_page_hint = get_freeish_page(0, MAKE_ATTR(256/N_WORD_BYTES, // spacing
713 CEILING(LAYOUT_SIZE,2),
714 0));
715 symbol_page_hint = get_freeish_page(0, MAKE_ATTR(CEILING(SYMBOL_SIZE,2),
716 CEILING(SYMBOL_SIZE,2),
717 0));
718 fdefn_page_hint = get_freeish_page(0, MAKE_ATTR(CEILING(FDEFN_SIZE,2),
719 CEILING(FDEFN_SIZE,2),
720 0));
723 void write_protect_immobile_space()
725 immobile_scav_queue = NULL;
726 immobile_scav_queue_head = 0;
728 set_immobile_space_hints();
730 // Now find contiguous ranges of pages that are protectable,
731 // minimizing the number of system calls as much as possible.
732 int i, start = -1, end = -1; // inclusive bounds on page indices
733 for (i = max_used_fixedobj_page ; i >= 0 ; --i) {
734 if (fixedobj_page_wp(i)) {
735 if (end < 0) end = i;
736 start = i;
738 if (end >= 0 && (!fixedobj_page_wp(i) || i == 0)) {
739 os_protect(low_page_address(start),
740 IMMOBILE_CARD_BYTES * (1 + end - start),
741 OS_VM_PROT_READ|OS_VM_PROT_EXECUTE);
742 start = end = -1;
745 #define varyobj_page_wp(x) !varyobj_page_touched(x)
746 for (i = max_used_varyobj_page ; i >= FIRST_VARYOBJ_PAGE ; --i) {
747 if (varyobj_page_wp(i)) {
748 if (end < 0) end = i;
749 start = i;
751 if (end >= 0 && (!varyobj_page_wp(i) || i == FIRST_VARYOBJ_PAGE)) {
752 os_protect(low_page_address(start),
753 IMMOBILE_CARD_BYTES * (1 + end - start),
754 OS_VM_PROT_READ|OS_VM_PROT_EXECUTE);
755 start = end = -1;
758 #undef varyobj_page_wp
761 // Scan range between start and end (exclusive) for old-to-young pointers.
762 // 'keep_gen' is the value of the generation byte of objects that were
763 // candidates to become garbage, but remain live after this gc.
764 // It will necessarily have the VISITED flag on.
765 // 'new_gen' is the generation number that those objects will have
766 // after collection, which is either the same generation or one higher,
767 // depending on the 'raise' flag for this GC cycle.
768 static int
769 range_points_to_younger_p(lispobj* obj, lispobj* end,
770 int gen, int keep_gen, int new_gen)
772 #ifdef DEBUG
773 lispobj* __attribute__((unused)) saved_obj = obj, __attribute__((unused)) header = *obj;
774 #endif
775 do {
776 lispobj thing = *obj;
777 if (is_lisp_pointer(thing)) {
778 int to_page = find_page_index((void*)thing),
779 to_gen = 255;
780 if (to_page >= 0) { // points to ordinary dynamic space
781 to_gen = page_table[to_page].gen;
782 if (to_gen == PSEUDO_STATIC_GENERATION+1) // scratch gen
783 to_gen = new_gen; // is actually this
784 } else if (immobile_space_p(thing)) {
785 // Processing the code-entry-points slot of a code component
786 // requires the general variant of immobile_obj_gen_bits
787 // because the pointed-to object is a simple-fun.
788 to_gen = immobile_obj_gen_bits(native_pointer(thing));
789 if (to_gen == keep_gen) // keep gen
790 to_gen = new_gen; // is actually this
792 if (to_gen < gen) {
793 return 1; // yes, points to younger
796 } while (++obj < end);
797 return 0; // no, does not point to younger
800 // Scan a fixed-size object for old-to-young pointers.
801 // Since fixed-size objects are boxed and on known boundaries,
802 // we never start in the middle of random bytes, so the answer is exact.
803 static inline boolean
804 fixedobj_points_to_younger_p(lispobj* obj, int n_words,
805 int gen, int keep_gen, int new_gen)
807 return range_points_to_younger_p(obj+1, obj+n_words,
808 gen, keep_gen, new_gen);
811 static boolean
812 varyobj_points_to_younger_p(lispobj* obj, int gen, int keep_gen, int new_gen,
813 os_vm_address_t page_begin,
814 os_vm_address_t page_end) // upper (exclusive) bound
816 lispobj *begin, *end, word = *obj;
817 unsigned char widetag = widetag_of(word);
818 if (widetag == CODE_HEADER_WIDETAG) { // usual case. Like scav_code_header()
819 for_each_simple_fun(i, function_ptr, (struct code*)obj, 0, {
820 begin = SIMPLE_FUN_SCAV_START(function_ptr);
821 end = begin + SIMPLE_FUN_SCAV_NWORDS(function_ptr);
822 if (page_begin > (os_vm_address_t)begin) begin = (lispobj*)page_begin;
823 if (page_end < (os_vm_address_t)end) end = (lispobj*)page_end;
824 if (end > begin
825 && range_points_to_younger_p(begin, end, gen, keep_gen, new_gen))
826 return 1;
828 begin = obj + 1; // skip the header
829 end = obj + code_header_words(word); // exclusive bound on boxed slots
830 } else if (widetag == SIMPLE_VECTOR_WIDETAG) {
831 sword_t length = fixnum_value(((struct vector *)obj)->length);
832 begin = obj + 2; // skip the header and length
833 end = obj + CEILING(length + 2, 2);
834 } else if (widetag >= SIMPLE_ARRAY_UNSIGNED_BYTE_2_WIDETAG &&
835 widetag <= MAXIMUM_STRING_WIDETAG) {
836 return 0;
837 } else {
838 lose("Unexpected widetag @ %p", obj);
840 // Fallthrough: scan words from begin to end
841 if (page_begin > (os_vm_address_t)begin) begin = (lispobj*)page_begin;
842 if (page_end < (os_vm_address_t)end) end = (lispobj*)page_end;
843 if (end > begin && range_points_to_younger_p(begin, end, gen, keep_gen, new_gen))
844 return 1;
845 return 0;
848 /// The next two functions are analogous to 'update_page_write_prot()'
849 /// but they differ in that they are "precise" - random code bytes that look
850 /// like pointers are not accidentally treated as pointers.
852 // If 'page' does not contain any objects that points to an object
853 // younger than themselves, then return true.
854 // This is called on pages that do not themselves contain objects of
855 // the generation being collected, but might contain pointers
856 // to younger generations, which we detect by a cleared WP status bit.
857 // The bit is cleared on any write, though, even of a non-pointer,
858 // so this unfortunately has to be tested much more often than we'd like.
859 static inline boolean can_wp_fixedobj_page(page_index_t page, int keep_gen, int new_gen)
861 int obj_spacing = page_obj_align(page) << WORD_SHIFT;
862 int obj_size_words = page_obj_size(page);
863 lispobj* obj = low_page_address(page);
864 lispobj* limit = (lispobj*)((char*)obj + IMMOBILE_CARD_BYTES - obj_spacing);
865 for ( ; obj <= limit ; obj = (lispobj*)((char*)obj + obj_spacing) )
866 if (!fixnump(*obj) && // an object header
867 fixedobj_points_to_younger_p(obj, obj_size_words,
868 __immobile_obj_generation(obj),
869 keep_gen, new_gen))
870 return 0;
871 return 1;
874 // To scan _only_ 'page' is impossible in general, but we can act like only
875 // one page was scanned by backing up to the first object whose end is on
876 // or after it, and then restricting points_to_younger within the boundaries.
877 // Doing it this way is probably much better than conservatively assuming
878 // that any word satisfying is_lisp_pointer() is a pointer.
879 static inline boolean can_wp_varyobj_page(page_index_t page, int keep_gen, int new_gen)
881 lispobj *begin = (lispobj*)low_page_address(page);
882 lispobj *end = begin + WORDS_PER_PAGE;
883 lispobj *obj = varyobj_scan_start(page);
884 for ( ; obj < end ; obj += sizetab[widetag_of(*obj)](obj) ) {
885 gc_assert(other_immediate_lowtag_p(*obj));
886 if (!immobile_filler_p(obj) &&
887 varyobj_points_to_younger_p(obj,
888 __immobile_obj_generation(obj),
889 keep_gen, new_gen,
890 (os_vm_address_t)begin,
891 (os_vm_address_t)end))
892 return 0;
894 return 1;
898 Sweep immobile space by zeroing the memory of trashed objects
899 and linking them into the freelist.
901 Possible improvements:
902 - If an entire page becomes nothing but holes, we could bzero it
903 instead of object-at-a-time clearing. But it's not known to be
904 so until after the sweep, so it would entail two passes per page,
905 one to mark holes and one to zero them.
906 - And perhaps bzero could be used on ranges of holes, because
907 in that case each hole's pointer to the next hole is zero as well.
910 #define SETUP_GENS() \
911 /* Only care about pages with something in old or new space. */ \
912 int relevant_genmask = (1 << from_space) | (1 << new_space); \
913 /* Objects whose gen byte is 'keep_gen' are alive. */ \
914 int keep_gen = IMMOBILE_OBJ_VISITED_FLAG | new_space; \
915 /* Objects whose gen byte is 'from_space' are trash. */ \
916 int discard_gen = from_space; \
917 /* Moving non-garbage into either 'from_space' or 'from_space+1' */ \
918 generation_index_t new_gen = from_space + (raise!=0)
920 // The new value of the page generation mask is computed as follows:
921 // If 'raise' = 1 then:
922 // Nothing resides in 'from_space', and 'from_space+1' gains new objects
923 // if and only if any objects on the page were retained.
924 // If 'raise' = 0 then:
925 // Nothing resides in the scratch generation, and 'from_space'
926 // has objects if and only if any objects were retained.
927 #define COMPUTE_NEW_MASK(var, old) \
928 int var = old & ~(1<<from_space); \
929 if ( raise ) \
930 var |= 1<<(from_space+1) & any_kept; \
931 else \
932 var = (var & ~(1<<new_space)) | (1<<from_space & any_kept)
934 static void
935 sweep_fixedobj_pages(int raise)
937 char *page_base;
938 lispobj *obj, *limit, *hole;
939 // This will be needed for space accounting.
940 // threads might fail to consume all the space on a page.
941 // By storing in the page table the count of holes that really existed
942 // at the start of the prior GC, and subtracting from that the number
943 // that exist now, we know how much usable space was obtained (per page).
944 int n_holes = 0;
945 int word_idx;
947 SETUP_GENS();
949 low_page_index_t page;
950 for (page = 0; page <= max_used_fixedobj_page; ++page) {
951 // On pages that won't need manipulation of the freelist,
952 // we try to do less work than for pages that need it.
953 if (!(fixedobj_pages[page].gens & relevant_genmask)) {
954 // Scan for old->young pointers, and WP if there are none.
955 if (!fixedobj_page_wp(page) && fixedobj_pages[page].gens > 1
956 && can_wp_fixedobj_page(page, keep_gen, new_gen))
957 SET_WP_FLAG(page, WRITE_PROTECT);
958 continue;
960 int obj_spacing = page_obj_align(page) << WORD_SHIFT;
961 int obj_size_words = page_obj_size(page);
962 page_base = low_page_address(page);
963 limit = (lispobj*)(page_base + IMMOBILE_CARD_BYTES - obj_spacing);
964 obj = (lispobj*)page_base;
965 hole = NULL;
966 int any_kept = 0; // was anything moved to the kept generation
967 n_holes = 0;
969 // wp_it is 1 if we should try to write-protect it now.
970 // If already write-protected, skip the tests.
971 int wp_it = !fixedobj_page_wp(page);
972 int gen;
973 for ( ; obj <= limit ; obj = (lispobj*)((char*)obj + obj_spacing) ) {
974 if (fixnump(*obj)) { // was already a hole
975 trash_it:
976 // re-link it into the new freelist
977 if (hole)
978 // store the displacement from the end of the object
979 // at prev_hole to the start of this object.
980 *hole = (lispobj)((char*)obj - ((char*)hole + obj_spacing));
981 else // this is the first seen hole on the page
982 // record the byte offset to that hole
983 fixedobj_pages[page].free_index = (char*)obj - page_base;
984 hole = obj;
985 n_holes ++;
986 } else if ((gen = __immobile_obj_gen_bits(obj)) == discard_gen) { // trash
987 for (word_idx=obj_size_words-1 ; word_idx > 0 ; --word_idx)
988 obj[word_idx] = 0;
989 goto trash_it;
990 } else if (gen == keep_gen) {
991 assign_generation(obj, gen = new_gen);
992 #ifdef DEBUG
993 gc_assert(!fixedobj_points_to_younger_p(obj, obj_size_words,
994 gen, keep_gen, new_gen));
995 #endif
996 any_kept = -1;
997 } else if (wp_it && fixedobj_points_to_younger_p(obj, obj_size_words,
998 gen, keep_gen, new_gen))
999 wp_it = 0;
1001 if ( hole ) // terminate the chain of holes
1002 *hole = (lispobj)((char*)obj - ((char*)hole + obj_spacing));
1003 fixedobj_pages[page].prior_gc_free_word_index =
1004 fixedobj_pages[page].free_index >> WORD_SHIFT;
1006 COMPUTE_NEW_MASK(mask, fixedobj_pages[page].gens);
1007 if ( mask ) {
1008 fixedobj_pages[page].gens = mask;
1009 if (wp_it) {
1010 SET_WP_FLAG(page, WRITE_PROTECT);
1011 dprintf((logfile, "Lowspace: set WP on page %d\n", page));
1013 } else {
1014 dprintf((logfile,"page %d is all garbage\n", page));
1015 fixedobj_pages[page].attr.packed = 0;
1017 #ifdef DEBUG
1018 check_fixedobj_page(page);
1019 #endif
1020 dprintf((logfile,"page %d: %d holes\n", page, n_holes));
1024 void verify_immobile_page_protection(int,int);
1026 // Scan for freshly trashed objects and turn them into filler.
1027 // Lisp is responsible for consuming the free space
1028 // when it next allocates a variable-size object.
1029 static void
1030 sweep_varyobj_pages(int raise)
1032 SETUP_GENS();
1034 lispobj* free_pointer = (lispobj*)SYMBOL(IMMOBILE_SPACE_FREE_POINTER)->value;
1035 low_page_index_t page;
1036 for (page = FIRST_VARYOBJ_PAGE; page <= max_used_varyobj_page; ++page) {
1037 int genmask = VARYOBJ_PAGE_GENS(page);
1038 if (!(genmask & relevant_genmask)) { // Has nothing in oldspace or newspace.
1039 // Scan for old->young pointers, and WP if there are none.
1040 if (varyobj_page_touched(page)
1041 && varyobj_page_gens_augmented(page) > 1
1042 && can_wp_varyobj_page(page, keep_gen, new_gen))
1043 varyobj_page_touched_bits[(page - FIRST_VARYOBJ_PAGE)/32] &= ~(1<<(page & 31));
1044 continue;
1046 lispobj* page_base = (lispobj*)low_page_address(page);
1047 lispobj* limit = page_base + WORDS_PER_PAGE;
1048 if (limit > free_pointer) limit = free_pointer;
1049 int any_kept = 0; // was anything moved to the kept generation
1050 // wp_it is 1 if we should try to write-protect it now.
1051 // If already write-protected, skip the tests.
1052 int wp_it = varyobj_page_touched(page);
1053 lispobj* obj = varyobj_scan_start(page);
1054 int size, gen;
1056 if (obj < page_base) {
1057 // An object whose tail is on this page, or which spans this page,
1058 // would have been promoted/kept while dealing with the page with
1059 // the object header. Therefore we don't need to consider that object,
1060 // * except * that we do need to consider whether it is an old object
1061 // pointing to a young object.
1062 if (wp_it // If we wanted to try write-protecting this page,
1063 // and the object starting before this page is strictly older
1064 // than the generation that we're moving retained objects into
1065 && (gen = __immobile_obj_gen_bits(obj)) > new_gen
1066 // and it contains an old->young pointer
1067 && varyobj_points_to_younger_p(obj, gen, keep_gen, new_gen,
1068 (os_vm_address_t)page_base,
1069 (os_vm_address_t)limit)) {
1070 wp_it = 0;
1072 // We MUST skip this object in the sweep, because in the case of
1073 // non-promotion (raise=0), we could see an object in from_space
1074 // and believe it to be dead.
1075 obj += sizetab[widetag_of(*obj)](obj);
1076 // obj can't hop over this page. If it did, there would be no
1077 // headers on the page, and genmask would have been zero.
1078 gc_assert(obj < limit);
1080 for ( ; obj < limit ; obj += size ) {
1081 lispobj word = *obj;
1082 size = sizetab[widetag_of(word)](obj);
1083 if (immobile_filler_p(obj)) { // do nothing
1084 } else if ((gen = __immobile_obj_gen_bits(obj)) == discard_gen) {
1085 if (size < 4)
1086 lose("immobile object @ %p too small to free", obj);
1087 else { // Create a filler object.
1088 struct code* code = (struct code*)obj;
1089 code->header = 2<<N_WIDETAG_BITS | CODE_HEADER_WIDETAG;
1090 code->code_size = make_fixnum((size - 2) * N_WORD_BYTES);
1091 code->debug_info = varyobj_holes;
1092 varyobj_holes = (lispobj)code;
1094 } else if (gen == keep_gen) {
1095 assign_generation(obj, gen = new_gen);
1096 #ifdef DEBUG
1097 gc_assert(!varyobj_points_to_younger_p(obj, gen, keep_gen, new_gen,
1098 (os_vm_address_t)page_base,
1099 (os_vm_address_t)limit));
1100 #endif
1101 any_kept = -1;
1102 } else if (wp_it &&
1103 varyobj_points_to_younger_p(obj, gen, keep_gen, new_gen,
1104 (os_vm_address_t)page_base,
1105 (os_vm_address_t)limit))
1106 wp_it = 0;
1108 COMPUTE_NEW_MASK(mask, VARYOBJ_PAGE_GENS(page));
1109 VARYOBJ_PAGE_GENS(page) = mask;
1110 if ( mask && wp_it )
1111 varyobj_page_touched_bits[(page - FIRST_VARYOBJ_PAGE)/32] &= ~(1 << (page & 31));
1113 #ifdef DEBUG
1114 verify_immobile_page_protection(keep_gen, new_gen);
1115 #endif
1118 static void compute_immobile_space_bound()
1120 int max;
1121 // find the highest page in use
1122 for (max = FIRST_VARYOBJ_PAGE-1 ; max >= 0 ; --max)
1123 if (fixedobj_pages[max].attr.parts.obj_size)
1124 break;
1125 max_used_fixedobj_page = max; // this is a page index, not the number of pages.
1126 SYMBOL(IMMOBILE_FIXEDOBJ_FREE_POINTER)->value =
1127 IMMOBILE_SPACE_START + IMMOBILE_CARD_BYTES*(1+max);
1129 for (max = (IMMOBILE_SPACE_SIZE/IMMOBILE_CARD_BYTES)-1 ;
1130 max >= FIRST_VARYOBJ_PAGE ; --max)
1131 if (varyobj_page_gens_augmented(max))
1132 break;
1133 max_used_varyobj_page = max; // this is a page index, not the number of pages.
1136 // TODO: (Maybe this won't work. Not sure yet.) rather than use the
1137 // same 'raise' concept as in gencgc, each immobile object can store bits
1138 // indicating whether it has survived any GC at its current generation.
1139 // If it has, then it gets promoted next time, rather than all or nothing
1140 // being promoted from the generation getting collected.
1141 void
1142 sweep_immobile_space(int raise)
1144 gc_assert(immobile_scav_queue_count == 0);
1145 sweep_fixedobj_pages(raise);
1146 sweep_varyobj_pages(raise);
1147 compute_immobile_space_bound();
1150 void gc_init_immobile()
1152 #ifdef DEBUG
1153 logfile = stderr;
1154 #endif
1155 int n_fixedobj_pages = FIRST_VARYOBJ_PAGE;
1156 int n_varyobj_pages = (IMMOBILE_SPACE_SIZE - IMMOBILE_FIXEDOBJ_SUBSPACE_SIZE)
1157 / IMMOBILE_CARD_BYTES;
1158 fixedobj_pages = calloc(n_fixedobj_pages, sizeof(struct fixedobj_page));
1159 gc_assert(fixedobj_pages);
1161 n_bitmap_elts = (n_varyobj_pages + 31) / 32;
1162 int request = n_bitmap_elts * sizeof (int)
1163 + n_varyobj_pages * (sizeof (short)+sizeof (char));
1164 char* varyobj_page_tables = malloc(request);
1165 gc_assert(varyobj_page_tables);
1166 memset(varyobj_page_tables, 0, request);
1167 varyobj_page_touched_bits = (unsigned int*)varyobj_page_tables;
1168 // The conservative value for 'touched' is 1.
1169 memset(varyobj_page_touched_bits, 0xff, n_bitmap_elts * sizeof (int));
1170 varyobj_page_scan_start_offset = (unsigned short*)(varyobj_page_touched_bits + n_bitmap_elts);
1171 varyobj_page_header_gens = (unsigned char*)(varyobj_page_scan_start_offset + n_varyobj_pages);
1174 /* Because the immobile page table is not dumped into a core image,
1175 we have to reverse-engineer the characteristics of each page,
1176 which means figuring out what the object spacing should be.
1177 This is not difficult, but is a bit of a kludge */
1179 static inline int immobile_obj_spacing(lispobj header_word, lispobj *obj,
1180 int actual_size)
1182 lispobj this_layout, layout_layout;
1184 // 64-bit build does not need to align layouts on 256-byte boundary.
1185 // But this is a proof-of-concept that should work on 32-bit build,
1186 // which would need the alignment if compact instance headers are used.
1187 if (widetag_of(header_word)==INSTANCE_HEADER_WIDETAG) {
1188 this_layout = instance_layout(obj);
1189 layout_layout = instance_layout(native_pointer(this_layout));
1190 // If this object's layout is layout-of-layout, then this is a layout,
1191 // hence this page must have object spacing of 256 bytes.
1192 if (this_layout == layout_layout)
1193 return 256 / N_WORD_BYTES;
1195 return actual_size; // in words
1198 // Set the characteristics of each used page at image startup time.
1199 void immobile_space_coreparse(uword_t address, uword_t len)
1201 int n_pages, word_idx, page;
1203 n_pages = (len + IMMOBILE_CARD_BYTES - 1) / IMMOBILE_CARD_BYTES;
1204 if (address == IMMOBILE_SPACE_START) {
1205 for (page = 0 ; page < n_pages ; ++page) {
1206 lispobj* page_data = low_page_address(page);
1207 for (word_idx = 0 ; word_idx < WORDS_PER_PAGE ; ++word_idx) {
1208 lispobj* obj = page_data + word_idx;
1209 lispobj header = *obj;
1210 if (!fixnump(header)) {
1211 gc_assert(other_immediate_lowtag_p(*obj));
1212 fixedobj_pages[page].attr.parts.obj_size
1213 = sizetab[widetag_of(header)](obj);
1214 fixedobj_pages[page].attr.parts.obj_align
1215 = immobile_obj_spacing(header, obj,
1216 fixedobj_pages[page].attr.parts.obj_size);
1217 fixedobj_pages[page].attr.parts.flags = WRITE_PROTECT;
1218 fixedobj_pages[page].gens |= 1 << __immobile_obj_gen_bits(obj);
1219 break;
1223 } else if (address == IMMOBILE_VARYOBJ_SUBSPACE_START) {
1224 lispobj* obj = (lispobj*)address;
1225 lispobj* limit = (lispobj*)(address + len);
1226 int n_words;
1227 low_page_index_t last_page = 0;
1228 for ( ; obj < limit ; obj += n_words ) {
1229 n_words = sizetab[widetag_of(*obj)](obj);
1230 if (obj[1] == 0 && (obj[0] == INSTANCE_HEADER_WIDETAG ||
1231 obj[0] == 0)) {
1232 if (obj[0]) {
1233 // Round up to the next immobile page.
1234 lispobj page_end = CEILING((lispobj)obj, IMMOBILE_CARD_BYTES);
1235 n_words = (lispobj*)page_end - obj;
1236 obj[0] = SIMPLE_ARRAY_FIXNUM_WIDETAG;
1237 obj[1] = make_fixnum(n_words - 2);
1238 } else {
1239 // There are trailing zeros to fill the core file page.
1240 // This happens when the next object is exactly aligned
1241 // to an immobile page. There is no padding object.
1242 gc_assert(((lispobj)obj & (IMMOBILE_CARD_BYTES-1)) == 0);
1244 limit = obj;
1245 break;
1247 if (immobile_filler_p(obj)) {
1248 // Holes were chained through the debug_info slot at save.
1249 // Just update the head of the chain.
1250 varyobj_holes = (lispobj)obj;
1251 continue;
1253 low_page_index_t first_page = find_immobile_page_index(obj);
1254 last_page = find_immobile_page_index(obj+n_words-1);
1255 // Only the page with this object header gets a bit in its gen mask.
1256 VARYOBJ_PAGE_GENS(first_page) |= 1<<__immobile_obj_gen_bits(obj);
1257 // For each page touched by this object, set the page's
1258 // scan_start_offset, unless it was already set.
1259 int page;
1260 for (page = first_page ; page <= last_page ; ++page) {
1261 if (!varyobj_page_scan_start_offset[page - FIRST_VARYOBJ_PAGE]) {
1262 long offset = (char*)low_page_address(page+1) - (char*)obj;
1263 varyobj_page_scan_start_offset[page - FIRST_VARYOBJ_PAGE]
1264 = offset >> (WORD_SHIFT + 1);
1268 // Write-protect the pages occupied by the core file.
1269 // (There can be no inter-generation pointers.)
1270 int page;
1271 for (page = FIRST_VARYOBJ_PAGE ; page <= last_page ; ++page)
1272 varyobj_page_touched_bits[(page-FIRST_VARYOBJ_PAGE)/32] &= ~(1<<(page & 31));
1273 SYMBOL(IMMOBILE_SPACE_FREE_POINTER)->value = (lispobj)limit;
1274 compute_immobile_space_bound();
1275 write_protect_immobile_space();
1276 } else {
1277 lose("unknown immobile subspace");
1281 // Demote pseudo-static to highest normal generation
1282 // so that all objects become eligible for collection.
1283 void prepare_immobile_space_for_final_gc()
1285 int page;
1286 char* page_base;
1287 char* page_end = (char*)SYMBOL(IMMOBILE_FIXEDOBJ_FREE_POINTER)->value;
1289 // The list of holes need not be saved.
1290 SYMBOL(IMMOBILE_FREELIST)->value = NIL;
1292 for (page_base = (char*)IMMOBILE_SPACE_START, page = 0 ;
1293 page_base < page_end ;
1294 page_base += IMMOBILE_CARD_BYTES, ++page) {
1295 unsigned char mask = fixedobj_pages[page].gens;
1296 if (mask & 1<<PSEUDO_STATIC_GENERATION) {
1297 int obj_spacing = page_obj_align(page) << WORD_SHIFT;
1298 lispobj* obj = (lispobj*)page_base;
1299 lispobj* limit = (lispobj*)(page_base + IMMOBILE_CARD_BYTES - obj_spacing);
1300 for ( ; obj <= limit ; obj = (lispobj*)((char*)obj + obj_spacing) ) {
1301 if (!fixnump(*obj)
1302 && __immobile_obj_gen_bits(obj) == PSEUDO_STATIC_GENERATION)
1303 assign_generation(obj, HIGHEST_NORMAL_GENERATION);
1305 fixedobj_pages[page].gens = (mask & ~(1<<PSEUDO_STATIC_GENERATION))
1306 | 1<<HIGHEST_NORMAL_GENERATION;
1310 lispobj* obj = (lispobj*)IMMOBILE_VARYOBJ_SUBSPACE_START;
1311 lispobj* limit = (lispobj*)SYMBOL(IMMOBILE_SPACE_FREE_POINTER)->value;
1312 for ( ; obj < limit ; obj += sizetab[widetag_of(*obj)](obj) ) {
1313 if (__immobile_obj_gen_bits(obj) == PSEUDO_STATIC_GENERATION)
1314 assign_generation(obj, HIGHEST_NORMAL_GENERATION);
1316 int max_page = find_immobile_page_index(limit-1);
1317 for ( page = FIRST_VARYOBJ_PAGE ; page <= max_page ; ++page ) {
1318 int mask = VARYOBJ_PAGE_GENS(page);
1319 if (mask & (1<<PSEUDO_STATIC_GENERATION)) {
1320 VARYOBJ_PAGE_GENS(page) = (mask & ~(1<<PSEUDO_STATIC_GENERATION))
1321 | 1<<HIGHEST_NORMAL_GENERATION;
1326 // Now once again promote all objects to pseudo-static just prior to save.
1327 // 'coreparse' makes all pages in regular dynamic space pseudo-static.
1328 // But since immobile objects store their generation, it must be done at save,
1329 // or else it would have to be done on image restart
1330 // which would require writing to a lot of pages for no reason.
1331 void prepare_immobile_space_for_save()
1333 int page;
1334 char *page_base;
1335 char* page_end = (char*)SYMBOL(IMMOBILE_FIXEDOBJ_FREE_POINTER)->value;
1337 for (page_base = (char*)IMMOBILE_SPACE_START, page = 0 ;
1338 page_base < page_end ;
1339 page_base += IMMOBILE_CARD_BYTES, ++page) {
1340 int obj_spacing = page_obj_align(page) << WORD_SHIFT;
1341 if (obj_spacing) {
1342 lispobj* obj = (lispobj*)page_base;
1343 lispobj* limit = (lispobj*)(page_base + IMMOBILE_CARD_BYTES - obj_spacing);
1344 for ( ; obj <= limit ; obj = (lispobj*)((char*)obj + obj_spacing) ) {
1345 if (!fixnump(*obj))
1346 assign_generation(obj, PSEUDO_STATIC_GENERATION);
1350 lispobj* obj = (lispobj*)IMMOBILE_VARYOBJ_SUBSPACE_START;
1351 lispobj* limit = (lispobj*)SYMBOL(IMMOBILE_SPACE_FREE_POINTER)->value;
1352 for ( varyobj_holes = 0 ; obj < limit ; obj += sizetab[widetag_of(*obj)](obj) ) {
1353 if (immobile_filler_p(obj)) {
1354 struct code* code = (struct code*)obj;
1355 code->debug_info = varyobj_holes;
1356 varyobj_holes = (lispobj)code;
1357 // 0-fill the unused space.
1358 int nwords = sizetab[widetag_of(*obj)](obj);
1359 memset(code->constants, 0,
1360 (nwords * N_WORD_BYTES) - offsetof(struct code, constants));
1361 } else
1362 assign_generation(obj, PSEUDO_STATIC_GENERATION);
1364 if ((lispobj)limit & (IMMOBILE_CARD_BYTES-1)) { // Last page is partially used.
1365 gc_assert(*limit == SIMPLE_ARRAY_FIXNUM_WIDETAG);
1366 // Write an otherwise illegal object at the free pointer.
1367 limit[0] = INSTANCE_HEADER_WIDETAG; // 0 payload length
1368 limit[1] = 0; // no layout
1372 //// Interface
1374 int immobile_space_handle_wp_violation(void* fault_addr)
1376 low_page_index_t page_index = find_immobile_page_index(fault_addr);
1377 if (page_index < 0) return 0;
1379 os_protect((os_vm_address_t)((lispobj)fault_addr & ~(IMMOBILE_CARD_BYTES-1)),
1380 IMMOBILE_CARD_BYTES, OS_VM_PROT_ALL);
1381 if (page_index >= FIRST_VARYOBJ_PAGE) {
1382 // The free pointer can move up or down. Attempting to insist that a WP
1383 // fault not occur above the free pointer (plus some slack) is not
1384 // threadsafe, so allow it anywhere. More strictness could be imparted
1385 // by tracking the max value attained by the free pointer.
1386 __sync_or_and_fetch(&varyobj_page_touched_bits[(page_index-FIRST_VARYOBJ_PAGE)/32],
1387 1 << (page_index & 31));
1388 } else {
1389 // FIXME: a single bitmap of touched bits would make more sense,
1390 // and the _CLEARED flag doesn't achieve much if anything.
1391 if (!(fixedobj_pages[page_index].attr.parts.flags
1392 & (WRITE_PROTECT|WRITE_PROTECT_CLEARED)))
1393 return 0;
1394 SET_WP_FLAG(page_index, WRITE_PROTECT_CLEARED);
1396 return 1;
1399 // Find the object that encloses pointer.
1400 lispobj *
1401 search_immobile_space(void *pointer)
1403 lispobj *start;
1405 if ((lispobj)pointer >= IMMOBILE_SPACE_START
1406 && (lispobj)pointer < SYMBOL(IMMOBILE_SPACE_FREE_POINTER)->value) {
1407 low_page_index_t page_index = find_immobile_page_index(pointer);
1408 if ((lispobj)pointer >= IMMOBILE_VARYOBJ_SUBSPACE_START) {
1409 start = (lispobj*)varyobj_scan_start(page_index);
1410 if (start > (lispobj*)pointer) return NULL;
1411 return (gc_search_space(start,
1412 (((lispobj*)pointer)+2)-start,
1413 (lispobj*)pointer));
1414 } else if ((lispobj)pointer < SYMBOL(IMMOBILE_FIXEDOBJ_FREE_POINTER)->value) {
1415 char *page_base = (char*)((lispobj)pointer & ~(IMMOBILE_CARD_BYTES-1));
1416 int spacing = page_obj_align(page_index) << WORD_SHIFT;
1417 int index = ((char*)pointer - page_base) / spacing;
1418 char *begin = page_base + spacing * index;
1419 char *end = begin + (page_obj_size(page_index) << WORD_SHIFT);
1420 if ((char*)pointer < end) return (lispobj*)begin;
1424 return NULL;
1427 // For coalescing holes, we need to scan backwards, which is done by
1428 // looking backwards for a page that contains the start of a
1429 // block of objects one of which must abut 'obj'.
1430 lispobj* find_preceding_object(lispobj* obj)
1432 int page = find_immobile_page_index(obj);
1433 while (1) {
1434 int offset = varyobj_page_scan_start_offset[page - FIRST_VARYOBJ_PAGE];
1435 if (offset) { // 0 means the page is empty.
1436 lispobj* start = varyobj_scan_start(page);
1437 if (start < obj) { // Scan from here forward
1438 while (1) {
1439 lispobj* end = start + sizetab[widetag_of(*start)](start);
1440 if (end == obj) return start;
1441 gc_assert(end < obj);
1442 start = end;
1446 if (page == FIRST_VARYOBJ_PAGE) {
1447 gc_assert(obj == low_page_address(FIRST_VARYOBJ_PAGE));
1448 return 0; // Predecessor does not exist
1450 --page;
1454 #include "genesis/vector.h"
1455 #include "genesis/instance.h"
1456 lispobj alloc_layout(lispobj layout_layout, lispobj slots)
1458 struct vector* v = (struct vector*)native_pointer(slots);
1459 // If INSTANCE_DATA_START is 0, subtract 1 word for the header.
1460 // If 1, subtract 2 words: 1 for the header and 1 for the layout.
1461 if (fixnum_value(v->length) != (LAYOUT_SIZE - INSTANCE_DATA_START - 1))
1462 lose("bad arguments to alloc_layout");
1463 struct instance* l = (struct instance*)
1464 alloc_immobile_obj(MAKE_ATTR(256 / N_WORD_BYTES,
1465 CEILING(LAYOUT_SIZE,2),
1467 #ifdef LISP_FEATURE_COMPACT_INSTANCE_HEADER
1468 (layout_layout << 32) |
1469 #endif
1470 (LAYOUT_SIZE-1)<<8 | INSTANCE_HEADER_WIDETAG,
1471 &layout_page_hint);
1472 #ifndef LISP_FEATURE_COMPACT_INSTANCE_HEADER
1473 l->slots[0] = layout_layout;
1474 #endif
1475 memcpy(&l->slots[INSTANCE_DATA_START], v->data,
1476 (LAYOUT_SIZE - INSTANCE_DATA_START - 1)*N_WORD_BYTES);
1478 // Possible efficiency win: make the "wasted" bytes after the layout into a
1479 // simple unboxed array so that heap-walking can skip in one step.
1480 // Probably only a performance issue for MAP-ALLOCATED-OBJECTS,
1481 // since scavenging know to skip by the object alignment anyway.
1482 return (lispobj)l | INSTANCE_POINTER_LOWTAG;
1485 #include "genesis/symbol.h"
1486 lispobj alloc_sym(lispobj name, int kind)
1488 // In case we want different kinds of symbol pages (as was the hope)
1489 // to keep special variables apart from random trash.
1490 // i.e. symbols whose page is often written versus symbols
1491 // that exist only as monikers. This would minimize the number
1492 // of different pages that become touched between GC cycles.
1493 int* hint = &symbol_page_hint;
1494 struct symbol* s = (struct symbol*)
1495 alloc_immobile_obj(MAKE_ATTR(CEILING(SYMBOL_SIZE,2), // spacing
1496 CEILING(SYMBOL_SIZE,2), // size
1497 kind),
1498 (SYMBOL_SIZE-1)<<8 | SYMBOL_HEADER_WIDETAG,
1499 hint);
1500 s->value = UNBOUND_MARKER_WIDETAG;
1501 s->hash = 0;
1502 s->info = NIL;
1503 s->name = name;
1504 s->package = NIL;
1505 return (lispobj)s | OTHER_POINTER_LOWTAG;
1508 #include "genesis/fdefn.h"
1509 lispobj alloc_fdefn(lispobj name)
1511 struct fdefn* f = (struct fdefn*)
1512 alloc_immobile_obj(MAKE_ATTR(CEILING(FDEFN_SIZE,2), // spacing
1513 CEILING(FDEFN_SIZE,2), // size
1515 (FDEFN_SIZE-1)<<8 | FDEFN_WIDETAG,
1516 &fdefn_page_hint);
1517 f->name = name;
1518 f->fun = NIL;
1519 f->raw_addr = 0;
1520 return (lispobj)f | OTHER_POINTER_LOWTAG;
1523 #ifdef LISP_FEATURE_IMMOBILE_CODE
1524 //// Defragmentation
1526 /// It's tricky to try to use the scavenging functions
1527 /// for fixing up moved code. There are a few reasons:
1528 /// - we need to rewrite the space on top of itself
1529 /// - we store forwarding pointers outside of the space
1530 /// - we'd want to modify the transport functions
1531 /// to deliberately fail in case one got called by mistake.
1532 /// So the approach is to basically do a large switch
1533 /// over all possible objects that we might need to fixup.
1534 /// There are some other strategies, none of which seem to
1535 /// make things obviously easier, such as:
1536 /// * variation (A)
1537 // Copy the whole space to a shadow space,
1538 /// deposit FPs in the real space but perform fixups
1539 /// in the shadow space; then copy it back.
1540 /// At least one problem here is that the chain of
1541 /// pointers in simple-funs in the shadow space
1542 /// has to compensate for their temporary address.
1543 /// * variation (B)
1544 /// First permute all code into the shadow space,
1545 /// copy it back, then fix it up. This is bad
1546 /// because we can't figure out original jump targets
1547 /// unless we have a reverse forwarding-pointer map.
1549 static char* tempspace;
1551 static void adjust_words(lispobj *where, sword_t n_words)
1553 int i;
1554 for (i=0;i<n_words;++i) {
1555 lispobj ptr;
1556 ptr = where[i];
1557 if (is_lisp_pointer(ptr) && immobile_space_p(ptr)
1558 && ptr >= IMMOBILE_VARYOBJ_SUBSPACE_START) {
1559 int offset_in_space = (lispobj)native_pointer(ptr) - IMMOBILE_VARYOBJ_SUBSPACE_START;
1560 lispobj* fp_where = (lispobj*)(tempspace + offset_in_space);
1561 where[i] = *fp_where;
1562 gc_assert(where[i]);
1567 static lispobj adjust_fun_entry(lispobj raw_entry)
1569 if (raw_entry > READ_ONLY_SPACE_END) {
1570 lispobj simple_fun = raw_entry - FUN_RAW_ADDR_OFFSET;
1571 adjust_words(&simple_fun, 1);
1572 return simple_fun + FUN_RAW_ADDR_OFFSET;
1574 return raw_entry; // for fdefn which has a tramp
1577 static void fixup_space(lispobj* where, size_t n_words)
1579 lispobj* end = where + n_words;
1580 lispobj header_word;
1581 int widetag;
1582 long size;
1584 while (where < end) {
1585 header_word = *where;
1586 if (is_lisp_pointer(header_word) || is_lisp_immediate(header_word)) {
1587 adjust_words(where, 2); // A cons.
1588 where += 2;
1589 continue;
1591 widetag = widetag_of(header_word);
1592 size = sizetab[widetag](where);
1593 switch (widetag) {
1594 default:
1595 if (!(widetag <= COMPLEX_DOUBLE_FLOAT_WIDETAG
1596 || widetag == SAP_WIDETAG // Better not point to code!
1597 || widetag == SIMD_PACK_WIDETAG
1598 || unboxed_array_p(widetag)))
1599 lose("Unhandled widetag in fixup_range: %p\n", (void*)header_word);
1600 break;
1601 case INSTANCE_HEADER_WIDETAG:
1602 instance_scan_interleaved(adjust_words, where,
1603 instance_length(header_word) | 1,
1604 native_pointer(instance_layout(where)));
1605 break;
1606 case CODE_HEADER_WIDETAG:
1607 // Fixup the constant pool.
1608 adjust_words(where+1, code_header_words(header_word)-1);
1609 // Fixup all embedded simple-funs
1610 for_each_simple_fun(i, f, (struct code*)where, 1, {
1611 f->self = adjust_fun_entry(f->self);
1612 adjust_words(SIMPLE_FUN_SCAV_START(f), SIMPLE_FUN_SCAV_NWORDS(f));
1614 break;
1615 case CLOSURE_HEADER_WIDETAG:
1616 where[1] = adjust_fun_entry(where[1]);
1617 // Fallthrough intended.
1618 case FUNCALLABLE_INSTANCE_HEADER_WIDETAG:
1619 // skip the trampoline word at where[1]
1620 adjust_words(where+2, HeaderValue(header_word)-1);
1621 break;
1622 case FDEFN_WIDETAG:
1623 adjust_words(where+1, 2);
1624 where[3] = adjust_fun_entry(where[3]);
1625 break;
1627 // All the array header widetags.
1628 case SIMPLE_VECTOR_WIDETAG:
1629 case SIMPLE_ARRAY_WIDETAG:
1630 #ifdef COMPLEX_CHARACTER_STRING_WIDETAG
1631 case COMPLEX_CHARACTER_STRING_WIDETAG:
1632 #endif
1633 case COMPLEX_BASE_STRING_WIDETAG:
1634 case COMPLEX_VECTOR_NIL_WIDETAG:
1635 case COMPLEX_BIT_VECTOR_WIDETAG:
1636 case COMPLEX_VECTOR_WIDETAG:
1637 case COMPLEX_ARRAY_WIDETAG:
1638 // And the other entirely boxed objects.
1639 case SYMBOL_HEADER_WIDETAG:
1640 case VALUE_CELL_HEADER_WIDETAG:
1641 case WEAK_POINTER_WIDETAG:
1642 case RATIO_WIDETAG:
1643 case COMPLEX_WIDETAG:
1644 // Use the sizing functions for generality.
1645 // Symbols can contain strange header bytes,
1646 // and vectors might have a padding word, etc.
1647 adjust_words(where+1, size-1);
1648 break;
1650 where += size;
1654 extern void
1655 walk_generation(void (*proc)(lispobj*,size_t),
1656 generation_index_t generation);
1658 // Both pointers are untagged.
1659 static void set_load_address(lispobj* old, lispobj new)
1661 int offset_in_space = (lispobj)old - IMMOBILE_VARYOBJ_SUBSPACE_START;
1662 lispobj* fp_loc = (lispobj*)(tempspace + offset_in_space);
1663 *fp_loc = new;
1665 // Take and return an untagged code pointer.
1666 static lispobj get_load_address(lispobj* old)
1668 int offset_in_space = (lispobj)old - IMMOBILE_VARYOBJ_SUBSPACE_START;
1669 lispobj* fp_loc = (lispobj*)(tempspace + offset_in_space);
1670 return *fp_loc;
1673 int* immobile_space_reloc_index;
1674 int* immobile_space_relocs;
1676 void defrag_immobile_space(int* components)
1678 long total_size = 0;
1679 lispobj* addr;
1680 int i;
1682 // Compute where each code component will be moved to.
1683 for (i=0 ; components[i*2] ; ++i) {
1684 addr = (lispobj*)(long)components[i*2];
1685 gc_assert(lowtag_of((lispobj)addr) == OTHER_POINTER_LOWTAG);
1686 addr = native_pointer((lispobj)addr);
1687 int widetag = widetag_of(*addr);
1688 lispobj new_vaddr = 0;
1689 // FIXME: generalize
1690 gc_assert(widetag == CODE_HEADER_WIDETAG);
1691 if (!immobile_filler_p(addr)) {
1692 new_vaddr = IMMOBILE_VARYOBJ_SUBSPACE_START + total_size;
1693 total_size += sizetab[widetag](addr) << WORD_SHIFT;
1695 components[i*2+1] = new_vaddr;
1697 // tempspace is the old total size, not the new total size,
1698 // because forwarding pointers are stashed there prior to defrag.
1699 // (It's a perfect hashtable by any other name.)
1700 size_t tempspace_bytes = (SYMBOL(IMMOBILE_SPACE_FREE_POINTER)->value
1701 - IMMOBILE_VARYOBJ_SUBSPACE_START);
1702 tempspace = calloc(tempspace_bytes, 1);
1704 // Deposit forwarding pointers into the temp space.
1705 lispobj new_vaddr;
1706 for (i=0 ; components[i*2] ; ++i) {
1707 if ((new_vaddr = components[i*2+1]) != 0) {
1708 addr = native_pointer(components[i*2]);
1709 int displacement = new_vaddr - (lispobj)addr;
1710 set_load_address(addr, new_vaddr);
1711 // FIXME: what is the 'if' for? Doesn't it _have_ to be code?
1712 if (widetag_of(*addr) == CODE_HEADER_WIDETAG)
1713 for_each_simple_fun(index, fun, (struct code*)addr, 1, {
1714 set_load_address((lispobj*)fun,
1715 make_lispobj((char*)fun + displacement,
1716 FUN_POINTER_LOWTAG));
1721 #ifdef LISP_FEATURE_X86_64
1722 // Fix displacements in JMP and CALL instructions
1723 for (i = 0 ; immobile_space_reloc_index[i*2] ; ++i) {
1724 lispobj code = immobile_space_reloc_index[i*2] - OTHER_POINTER_LOWTAG;
1725 lispobj load_addr = 0;
1726 if (code >= READ_ONLY_SPACE_START && code < READ_ONLY_SPACE_END)
1727 load_addr = code; // This code can not be moved or GCed.
1728 else
1729 load_addr = get_load_address((lispobj*)code);
1730 if (load_addr) { // Skip any code that was dropped by GC.
1731 int reloc_index = immobile_space_reloc_index[i*2+1];
1732 int end_reloc_index = immobile_space_reloc_index[i*2+3];
1733 for ( ; reloc_index < end_reloc_index ; ++reloc_index ) {
1734 unsigned char* inst_addr = (unsigned char*)(long)immobile_space_relocs[reloc_index];
1735 gc_assert(*inst_addr == 0xE8 || *inst_addr == 0xE9);
1736 unsigned int target_addr = (int)(long)inst_addr + 5 + *(int*)(inst_addr+1);
1737 int target_adjust = 0;
1738 if (target_addr >= IMMOBILE_VARYOBJ_SUBSPACE_START && target_addr < IMMOBILE_SPACE_END) {
1739 lispobj* ptarg_fun_header =
1740 (lispobj*)(target_addr - offsetof(struct simple_fun, code));
1741 gc_assert(widetag_of(*ptarg_fun_header) == SIMPLE_FUN_HEADER_WIDETAG);
1742 lispobj* ptarg_code_header =
1743 ptarg_fun_header - HeaderValue(*ptarg_fun_header);
1744 gc_assert(widetag_of(*ptarg_code_header) == CODE_HEADER_WIDETAG);
1745 lispobj targ_load_addr = get_load_address(ptarg_code_header);
1746 gc_assert(targ_load_addr); // was not discarded
1747 target_adjust = targ_load_addr - (lispobj)ptarg_code_header;
1749 *(int*)(inst_addr+1) += target_adjust + ((lispobj)code - load_addr);
1753 #endif
1754 free(immobile_space_relocs);
1755 free(immobile_space_reloc_index);
1757 // Fix Lisp pointers in static, immobile, and dynamic spaces
1758 fixup_space((lispobj*)STATIC_SPACE_START,
1759 (SYMBOL(STATIC_SPACE_FREE_POINTER)->value
1760 - STATIC_SPACE_START) >> WORD_SHIFT);
1761 fixup_space((lispobj*)IMMOBILE_SPACE_START,
1762 (SYMBOL(IMMOBILE_FIXEDOBJ_FREE_POINTER)->value
1763 - IMMOBILE_SPACE_START) >> WORD_SHIFT);
1764 fixup_space((lispobj*)IMMOBILE_VARYOBJ_SUBSPACE_START,
1765 (SYMBOL(IMMOBILE_SPACE_FREE_POINTER)->value
1766 - IMMOBILE_VARYOBJ_SUBSPACE_START) >> WORD_SHIFT);
1767 walk_generation(fixup_space, -1);
1769 // Now permute the code components
1770 for (i=0 ; components[i*2] ; ++i) {
1771 if ((new_vaddr = components[i*2+1]) != 0) {
1772 addr = native_pointer(components[i*2]);
1773 char* to_addr = tempspace + ((char*)new_vaddr - (char*)IMMOBILE_VARYOBJ_SUBSPACE_START);
1774 size_t size = sizetab[widetag_of(*addr)](addr) << WORD_SHIFT;
1775 memcpy(to_addr, addr, size);
1778 // Copy the permuted space back where it belongs.
1779 memcpy((char*)IMMOBILE_VARYOBJ_SUBSPACE_START, tempspace, total_size);
1781 // Zero-fill the unused remainder of the immobile space
1782 lispobj free_ptr = IMMOBILE_VARYOBJ_SUBSPACE_START + total_size;
1783 lispobj old_free_ptr = SYMBOL(IMMOBILE_SPACE_FREE_POINTER)->value;
1784 bzero((char*)free_ptr, old_free_ptr - free_ptr);
1785 SYMBOL(IMMOBILE_SPACE_FREE_POINTER)->value = free_ptr;
1786 if (free_ptr & (IMMOBILE_CARD_BYTES-1)) { // unless page-aligned
1787 int remainder = IMMOBILE_CARD_BYTES - (free_ptr & (IMMOBILE_CARD_BYTES-1));
1788 ((lispobj*)free_ptr)[0] = SIMPLE_ARRAY_FIXNUM_WIDETAG;
1789 ((lispobj*)free_ptr)[1] = make_fixnum((remainder >> WORD_SHIFT) - 2);
1792 free(tempspace);
1793 free(components);
1795 #endif
1797 void verify_immobile_page_protection(int keep_gen, int new_gen)
1799 low_page_index_t page;
1800 lispobj* end = (lispobj*)SYMBOL(IMMOBILE_SPACE_FREE_POINTER)->value;
1801 low_page_index_t end_page = find_immobile_page_index((char*)end-1);
1802 lispobj* obj;
1804 for (page = FIRST_VARYOBJ_PAGE; page <= end_page; ++page) {
1805 if (!varyobj_page_touched(page)) {
1806 lispobj* page_begin = low_page_address(page);
1807 lispobj* page_end = page_begin + WORDS_PER_PAGE;
1808 // Assert that there are no old->young pointers.
1809 obj = varyobj_scan_start(page);
1810 // Never scan past the free pointer.
1811 // FIXME: It is is supposed to work to scan past the free pointer
1812 // on the last page, but the allocator needs to plop an array header there,
1813 // and sometimes it doesn't.
1814 lispobj* varyobj_free_ptr = (lispobj*)(SYMBOL(IMMOBILE_SPACE_FREE_POINTER)->value);
1815 if (page_end > varyobj_free_ptr) page_end = varyobj_free_ptr;
1816 for ( ; obj < page_end ; obj += sizetab[widetag_of(*obj)](obj) ) {
1817 if (!immobile_filler_p(obj)
1818 && varyobj_points_to_younger_p(obj, __immobile_obj_gen_bits(obj),
1819 keep_gen, new_gen,
1820 (char*)page_begin, (char*)page_end))
1821 lose("page WP bit on page %d is wrong\n", page);
1827 #ifdef VERIFY_PAGE_GENS
1828 void check_fixedobj_page(int page)
1830 // Every page should have a 'gens' mask which exactly reflects
1831 // the aggregate over all objects on that page. Verify that invariant,
1832 // checking all pages, not just the ones below the free pointer.
1833 int genmask, obj_size, obj_spacing, i, all_ok = 1;
1834 lispobj *obj, *limit, header;
1835 int sees_younger = 0;
1837 obj_size = page_obj_size(page);
1838 obj_spacing = page_obj_align(page);
1839 obj = low_page_address(page);
1840 limit = obj + WORDS_PER_PAGE - obj_spacing;
1841 genmask = 0;
1842 if (obj_size == 0) {
1843 for (i=0; i<WORDS_PER_PAGE; ++i)
1844 gc_assert(obj[i]==0);
1845 gc_assert(fixedobj_pages[page].gens ==0);
1846 return;
1848 for ( ; obj <= limit ; obj += obj_spacing ) {
1849 header = *obj;
1850 if (!fixnump(header)) {
1851 int gen = __immobile_obj_gen_bits(obj);
1852 gc_assert(0 <= gen && gen <= PSEUDO_STATIC_GENERATION);
1853 genmask |= 1<<gen;
1854 if (fixedobj_points_to_younger_p(obj, obj_size, gen, 0xff, 0xff))
1855 sees_younger = 1;
1858 // It's not wrong if the gen0 bit is set spuriously, but it should only
1859 // happen at most once, on the first GC after image startup.
1860 // At all other times, the invariant should hold that if the freelist
1861 // indicated that space was available, and the new pointer differs,
1862 // then some gen0 object exists on the page.
1863 // The converse is true because of pseudo-atomicity of the allocator:
1864 // if some thread claimed a hole, then it also updated the freelist.
1865 // If it died before doing the latter, then the object allegedly created
1866 // was never really live, so won't contain any pointers.
1867 if (fixedobj_pages[page].gens != genmask
1868 && fixedobj_pages[page].gens != (genmask|1)) {
1869 fprintf(stderr, "Page #x%x @ %p: stored mask=%x actual=%x\n",
1870 page, low_page_address(page),
1871 fixedobj_pages[page].gens, genmask);
1872 all_ok = 0;
1874 if (fixedobj_page_wp(page) && sees_younger) {
1875 fprintf(stderr, "Page #x%x @ %p: WP is wrong\n",
1876 page, low_page_address(page));
1877 all_ok = 0;
1879 gc_assert(all_ok);
1882 int n_immobile_objects;
1883 int *immobile_objects, *immobile_objects_limit;
1885 int comparator_eq(const void* a, const void* b) {
1886 return *(int*)a - *(int*)b;
1889 // Find the largest item less than or equal.
1890 // (useful for finding the object that contains a given pointer)
1891 int comparator_le(const void* a, const void* b) {
1892 int diff = *(int*)a - *(int*)b;
1893 if (diff <= 0) return diff;
1894 // If looking to the right would see an item strictly greater
1895 // than the sought key, or there is nothing to the right,
1896 // then deem this an exact match.
1897 if (b == (void*)immobile_objects_limit || ((int*)b)[1] > *(int*)a) return 0;
1898 return 1;
1901 // Find the smallest item greater than or equal.
1902 // useful for finding the lowest item at or after a page base address.
1903 int comparator_ge(const void* a, const void* b) {
1904 int diff = *(int*)a - *(int*)b;
1905 if (diff >= 0) return diff;
1906 // If looking to the left would see an item strictly less
1907 // than the sought key, or there is nothing to the left
1908 // then deem this an exact match.
1909 if (b == (void*)immobile_objects || ((int*)b)[-1] < *(int*)a) return 0;
1910 return -1;
1913 void check_varyobj_pages()
1915 // 1. Check that a linear scan sees only valid object headers,
1916 // and that it terminates exactly at IMMOBILE_CODE_FREE_POINTER.
1917 lispobj* obj = (lispobj*)IMMOBILE_VARYOBJ_SUBSPACE_START;
1918 lispobj* end = (lispobj*)SYMBOL(IMMOBILE_SPACE_FREE_POINTER)->value;
1919 low_page_index_t end_page = find_immobile_page_index((char*)end-1);
1921 n_immobile_objects = 0;
1922 while (obj < end) {
1923 lispobj word = *obj;
1924 gc_assert(other_immediate_lowtag_p(word));
1925 int n_words = sizetab[widetag_of(word)](obj);
1926 obj += n_words;
1927 ++n_immobile_objects;
1929 gc_assert(obj == end);
1931 // 2. Check that all scan_start_offsets are plausible.
1932 // Begin by collecting all object header locations into an array;
1933 immobile_objects = calloc(n_immobile_objects, sizeof (lispobj));
1934 immobile_objects_limit = immobile_objects + n_immobile_objects - 1;
1935 obj = (lispobj*)IMMOBILE_VARYOBJ_SUBSPACE_START;
1936 int i = 0;
1937 while (obj < end) {
1938 immobile_objects[i++] = (lispobj)obj;
1939 lispobj word = *obj;
1940 int n_words = sizetab[widetag_of(word)](obj);
1941 obj += n_words;
1943 // Check that each page's scan start is a known immobile object
1944 // and that it is the right object.
1945 low_page_index_t page;
1946 for (page = FIRST_VARYOBJ_PAGE; page <= end_page; ++page) {
1947 lispobj page_addr = (lispobj)low_page_address(page);
1948 int* found_below = bsearch(&page_addr, immobile_objects, n_immobile_objects,
1949 sizeof (int), comparator_le);
1950 int* found_above = bsearch(&page_addr, immobile_objects, n_immobile_objects,
1951 sizeof (int), comparator_ge);
1952 int stored_scan_start = (int)(long)varyobj_scan_start(page);
1953 lispobj* scan_start_obj = (lispobj*)(long)*found_below;
1954 if (scan_start_obj != (lispobj*)(long)stored_scan_start) {
1955 //printf("page %d: found-below=%p stored=%p\n", page, scan_start_obj, stored_scan_start);
1956 while (immobile_filler_p(scan_start_obj)) {
1957 int nwords = sizetab[widetag_of(*scan_start_obj)](scan_start_obj);
1958 // printf("skipping %d words to %p\n", nwords, scan_start_obj + nwords);
1959 scan_start_obj += nwords;
1960 // the stored scan start does not guarantee that it points
1961 // to a non-hole; we only assert that it *probably* does not.
1962 // As such, when computing the "correct" value, we allow
1963 // any value in between the legal bounding values for it.
1964 if ((int)(long)scan_start_obj == stored_scan_start)
1965 break;
1966 // If you hit the free pointer, or run off the page,
1967 // then the page is completely empty.
1968 if (scan_start_obj == (lispobj*)SYMBOL(IMMOBILE_SPACE_FREE_POINTER)->value
1969 || scan_start_obj >= (lispobj*)low_page_address(page+1)) {
1970 scan_start_obj = low_page_address(page+1);
1971 break;
1975 if (scan_start_obj != (lispobj*)(long)stored_scan_start)
1976 lose("page %d: stored_scan_start=%p does not match found %p\n",
1977 page, stored_scan_start, *found_below);
1978 if (found_below != found_above) {
1979 // the object below must touch this page.
1980 // if it didn't, there should be a higher object below.
1981 lispobj* below = (lispobj*)(long)*found_below;
1982 int n_words = sizetab[widetag_of(*below)](below);
1983 lispobj* end = below + n_words;
1984 gc_assert(end > (lispobj*)page_addr);
1987 free(immobile_objects);
1989 // 3. The generation mask for each page is exactly the union
1990 // of generation numbers of object headers on the page.
1991 for (page = FIRST_VARYOBJ_PAGE; page <= end_page; ++page) {
1992 if (!varyobj_page_scan_start_offset[page - FIRST_VARYOBJ_PAGE])
1993 continue; // page is all holes or never used
1994 obj = varyobj_scan_start(page);
1995 lispobj word = *obj;
1996 int n_words = sizetab[widetag_of(word)](obj);
1997 // Skip the first object if it doesn't start on this page.
1998 if (obj < (lispobj*)low_page_address(page)) obj += n_words;
1999 lispobj* limit = (lispobj*)low_page_address(page) + WORDS_PER_PAGE;
2000 lispobj* freeptr = (lispobj*)SYMBOL(IMMOBILE_SPACE_FREE_POINTER)->value;
2001 if (limit > freeptr) limit = freeptr;
2002 int mask = 0;
2003 for ( ; obj < limit ; obj += sizetab[widetag_of(*obj)](obj) ) {
2004 int gen = __immobile_obj_gen_bits(obj);
2005 if (immobile_filler_p(obj)) {
2006 gc_assert(gen == 0);
2007 } else {
2008 gc_assert(0 <= gen && gen <= PSEUDO_STATIC_GENERATION);
2009 mask |= 1 << gen;
2011 if (widetag_of(*obj) == CODE_HEADER_WIDETAG) {
2012 lispobj entry_point; /* tagged pointer to entry point */
2013 struct simple_fun *function_ptr; /* untagged pointer to entry point */
2014 for (entry_point = ((struct code*)obj)->entry_points;
2015 entry_point != NIL;
2016 entry_point = function_ptr->next) {
2017 function_ptr = (struct simple_fun *) native_pointer(entry_point);
2018 gc_assert_verbose(is_lisp_pointer(entry_point),
2019 "Code %p entry point %p is not a lisp pointer.",
2020 obj, (void*)entry_point);
2021 gc_assert(widetag_of(function_ptr->header)==SIMPLE_FUN_HEADER_WIDETAG);
2025 gc_assert(mask == VARYOBJ_PAGE_GENS(page));
2028 #endif