11ddcfdf723425ccc3995e92e6a05fe8e8839dca
[sbcl.git] / src / runtime / gencgc.c
1 /*
2  * GENerational Conservative Garbage Collector for SBCL x86
3  */
4
5 /*
6  * This software is part of the SBCL system. See the README file for
7  * more information.
8  *
9  * This software is derived from the CMU CL system, which was
10  * written at Carnegie Mellon University and released into the
11  * public domain. The software is in the public domain and is
12  * provided with absolutely no warranty. See the COPYING and CREDITS
13  * files for more information.
14  */
15
16 /*
17  * For a review of garbage collection techniques (e.g. generational
18  * GC) and terminology (e.g. "scavenging") see Paul R. Wilson,
19  * "Uniprocessor Garbage Collection Techniques". As of 20000618, this
20  * had been accepted for _ACM Computing Surveys_ and was available
21  * as a PostScript preprint through
22  *   <http://www.cs.utexas.edu/users/oops/papers.html>
23  * as
24  *   <ftp://ftp.cs.utexas.edu/pub/garbage/bigsurv.ps>.
25  */
26
27 /*
28  * FIXME: GC :FULL T seems to be unable to recover a lot of unused
29  * space. After cold init is complete, GC :FULL T gets us down to
30  * about 44 Mb total used, but PURIFY gets us down to about 17 Mb
31  * total used.
32  */
33
34 #include <stdio.h>
35 #include <signal.h>
36 #include "runtime.h"
37 #include "sbcl.h"
38 #include "os.h"
39 #include "interr.h"
40 #include "globals.h"
41 #include "interrupt.h"
42 #include "validate.h"
43 #include "lispregs.h"
44 #include "arch.h"
45 #include "gc.h"
46 #include "gencgc.h"
47
48 /* a function defined externally in assembly language, called from
49  * this file */
50 void do_pending_interrupt(void);
51 \f
52 /*
53  * GC parameters
54  */
55
56 /* the number of actual generations. (The number of 'struct
57  * generation' objects is one more than this, because one serves as
58  * scratch when GC'ing.) */
59 #define NUM_GENERATIONS 6
60
61 /* Should we use page protection to help avoid the scavenging of pages
62  * that don't have pointers to younger generations? */
63 boolean enable_page_protection = 1;
64
65 /* Should we unmap a page and re-mmap it to have it zero filled? */
66 #if defined(__FreeBSD__) || defined(__OpenBSD__)
67 /* comment from cmucl-2.4.8: This can waste a lot of swap on FreeBSD
68  * so don't unmap there.
69  *
70  * The CMU CL comment didn't specify a version, but was probably an
71  * old version of FreeBSD (pre-4.0), so this might no longer be true.
72  * OTOH, if it is true, this behavior might exist on OpenBSD too, so
73  * for now we don't unmap there either. -- WHN 2001-04-07 */
74 boolean gencgc_unmap_zero = 0;
75 #else
76 boolean gencgc_unmap_zero = 1;
77 #endif
78
79 /* the minimum size (in bytes) for a large object*/
80 unsigned large_object_size = 4 * 4096;
81
82 /* Should we filter stack/register pointers? This could reduce the
83  * number of invalid pointers accepted. KLUDGE: It will probably
84  * degrades interrupt safety during object initialization. */
85 boolean enable_pointer_filter = 1;
86 \f
87 /*
88  * debugging
89  */
90
91 #define gc_abort() lose("GC invariant lost, file \"%s\", line %d", \
92                         __FILE__, __LINE__)
93
94 /* FIXME: In CMU CL, this was "#if 0" with no explanation. Find out
95  * how much it costs to make it "#if 1". If it's not too expensive,
96  * keep it. */
97 #if 1
98 #define gc_assert(ex) do { \
99         if (!(ex)) gc_abort(); \
100 } while (0)
101 #else
102 #define gc_assert(ex)
103 #endif
104
105 /* the verbosity level. All non-error messages are disabled at level 0;
106  * and only a few rare messages are printed at level 1. */
107 unsigned gencgc_verbose = (QSHOW ? 1 : 0);
108
109 /* FIXME: At some point enable the various error-checking things below
110  * and see what they say. */
111
112 /* We hunt for pointers to old-space, when GCing generations >= verify_gen.
113  * Set verify_gens to NUM_GENERATIONS to disable this kind of check. */
114 int verify_gens = NUM_GENERATIONS;
115
116 /* Should we do a pre-scan verify of generation 0 before it's GCed? */
117 boolean pre_verify_gen_0 = 0;
118
119 /* Should we check for bad pointers after gc_free_heap is called
120  * from Lisp PURIFY? */
121 boolean verify_after_free_heap = 0;
122
123 /* Should we print a note when code objects are found in the dynamic space
124  * during a heap verify? */
125 boolean verify_dynamic_code_check = 0;
126
127 /* Should we check code objects for fixup errors after they are transported? */
128 boolean check_code_fixups = 0;
129
130 /* Should we check that newly allocated regions are zero filled? */
131 boolean gencgc_zero_check = 0;
132
133 /* Should we check that the free space is zero filled? */
134 boolean gencgc_enable_verify_zero_fill = 0;
135
136 /* Should we check that free pages are zero filled during gc_free_heap
137  * called after Lisp PURIFY? */
138 boolean gencgc_zero_check_during_free_heap = 0;
139 \f
140 /*
141  * GC structures and variables
142  */
143
144 /* the total bytes allocated. These are seen by Lisp DYNAMIC-USAGE. */
145 unsigned long bytes_allocated = 0;
146 static unsigned long auto_gc_trigger = 0;
147
148 /* the source and destination generations. These are set before a GC starts
149  * scavenging. */
150 static int from_space;
151 static int new_space;
152
153 /* FIXME: It would be nice to use this symbolic constant instead of
154  * bare 4096 almost everywhere. We could also use an assertion that
155  * it's equal to getpagesize(). */
156 #define PAGE_BYTES 4096
157
158 /* An array of page structures is statically allocated.
159  * This helps quickly map between an address its page structure.
160  * NUM_PAGES is set from the size of the dynamic space. */
161 struct page page_table[NUM_PAGES];
162
163 /* To map addresses to page structures the address of the first page
164  * is needed. */
165 static void *heap_base = NULL;
166
167 /* Calculate the start address for the given page number. */
168 inline void
169 *page_address(int page_num)
170 {
171     return (heap_base + (page_num * 4096));
172 }
173
174 /* Find the page index within the page_table for the given
175  * address. Return -1 on failure. */
176 inline int
177 find_page_index(void *addr)
178 {
179     int index = addr-heap_base;
180
181     if (index >= 0) {
182         index = ((unsigned int)index)/4096;
183         if (index < NUM_PAGES)
184             return (index);
185     }
186
187     return (-1);
188 }
189
190 /* a structure to hold the state of a generation */
191 struct generation {
192
193     /* the first page that gc_alloc checks on its next call */
194     int alloc_start_page;
195
196     /* the first page that gc_alloc_unboxed checks on its next call */
197     int alloc_unboxed_start_page;
198
199     /* the first page that gc_alloc_large (boxed) considers on its next
200      * call. (Although it always allocates after the boxed_region.) */
201     int alloc_large_start_page;
202
203     /* the first page that gc_alloc_large (unboxed) considers on its
204      * next call. (Although it always allocates after the
205      * current_unboxed_region.) */
206     int alloc_large_unboxed_start_page;
207
208     /* the bytes allocated to this generation */
209     int bytes_allocated;
210
211     /* the number of bytes at which to trigger a GC */
212     int gc_trigger;
213
214     /* to calculate a new level for gc_trigger */
215     int bytes_consed_between_gc;
216
217     /* the number of GCs since the last raise */
218     int num_gc;
219
220     /* the average age after which a GC will raise objects to the
221      * next generation */
222     int trigger_age;
223
224     /* the cumulative sum of the bytes allocated to this generation. It is
225      * cleared after a GC on this generations, and update before new
226      * objects are added from a GC of a younger generation. Dividing by
227      * the bytes_allocated will give the average age of the memory in
228      * this generation since its last GC. */
229     int cum_sum_bytes_allocated;
230
231     /* a minimum average memory age before a GC will occur helps
232      * prevent a GC when a large number of new live objects have been
233      * added, in which case a GC could be a waste of time */
234     double min_av_mem_age;
235 };
236
237 /* an array of generation structures. There needs to be one more
238  * generation structure than actual generations as the oldest
239  * generation is temporarily raised then lowered. */
240 static struct generation generations[NUM_GENERATIONS+1];
241
242 /* the oldest generation that is will currently be GCed by default.
243  * Valid values are: 0, 1, ... (NUM_GENERATIONS-1)
244  *
245  * The default of (NUM_GENERATIONS-1) enables GC on all generations.
246  *
247  * Setting this to 0 effectively disables the generational nature of
248  * the GC. In some applications generational GC may not be useful
249  * because there are no long-lived objects.
250  *
251  * An intermediate value could be handy after moving long-lived data
252  * into an older generation so an unnecessary GC of this long-lived
253  * data can be avoided. */
254 unsigned int  gencgc_oldest_gen_to_gc = NUM_GENERATIONS-1;
255
256 /* The maximum free page in the heap is maintained and used to update
257  * ALLOCATION_POINTER which is used by the room function to limit its
258  * search of the heap. XX Gencgc obviously needs to be better
259  * integrated with the Lisp code. */
260 static int  last_free_page;
261 static int  last_used_page = 0;
262 \f
263 /*
264  * miscellaneous heap functions
265  */
266
267 /* Count the number of pages which are write-protected within the
268  * given generation. */
269 static int
270 count_write_protect_generation_pages(int generation)
271 {
272     int i;
273     int cnt = 0;
274
275     for (i = 0; i < last_free_page; i++)
276         if ((page_table[i].allocated != FREE_PAGE)
277             && (page_table[i].gen == generation)
278             && (page_table[i].write_protected == 1))
279             cnt++;
280     return(cnt);
281 }
282
283 /* Count the number of pages within the given generation */
284 static int
285 count_generation_pages(int generation)
286 {
287     int i;
288     int cnt = 0;
289
290     for (i = 0; i < last_free_page; i++)
291         if ((page_table[i].allocated != 0)
292             && (page_table[i].gen == generation))
293             cnt++;
294     return(cnt);
295 }
296
297 /* Count the number of dont_move pages. */
298 static int
299 count_dont_move_pages(void)
300 {
301     int i;
302     int cnt = 0;
303
304     for (i = 0; i < last_free_page; i++)
305         if ((page_table[i].allocated != 0)
306             && (page_table[i].dont_move != 0))
307             cnt++;
308     return(cnt);
309 }
310
311 /* Work through the pages and add up the number of bytes used for the
312  * given generation. */
313 static int
314 generation_bytes_allocated (int gen)
315 {
316     int i;
317     int result = 0;
318
319     for (i = 0; i < last_free_page; i++) {
320         if ((page_table[i].allocated != 0) && (page_table[i].gen == gen))
321             result += page_table[i].bytes_used;
322     }
323     return result;
324 }
325
326 /* Return the average age of the memory in a generation. */
327 static double
328 gen_av_mem_age(int gen)
329 {
330     if (generations[gen].bytes_allocated == 0)
331         return 0.0;
332
333     return
334         ((double)generations[gen].cum_sum_bytes_allocated)
335         / ((double)generations[gen].bytes_allocated);
336 }
337
338 /* The verbose argument controls how much to print: 0 for normal
339  * level of detail; 1 for debugging. */
340 static void
341 print_generation_stats(int verbose) /* FIXME: should take FILE argument */
342 {
343     int i, gens;
344     int fpu_state[27];
345
346     /* This code uses the FP instructions which may be set up for Lisp
347      * so they need to be saved and reset for C. */
348     fpu_save(fpu_state);
349
350     /* number of generations to print */
351     if (verbose)
352         gens = NUM_GENERATIONS+1;
353     else
354         gens = NUM_GENERATIONS;
355
356     /* Print the heap stats. */
357     fprintf(stderr,
358             "   Generation Boxed Unboxed LB   LUB    Alloc  Waste   Trig    WP  GCs Mem-age\n");
359
360     for (i = 0; i < gens; i++) {
361         int j;
362         int boxed_cnt = 0;
363         int unboxed_cnt = 0;
364         int large_boxed_cnt = 0;
365         int large_unboxed_cnt = 0;
366
367         for (j = 0; j < last_free_page; j++)
368             if (page_table[j].gen == i) {
369
370                 /* Count the number of boxed pages within the given
371                  * generation. */
372                 if (page_table[j].allocated == BOXED_PAGE) {
373                     if (page_table[j].large_object)
374                         large_boxed_cnt++;
375                     else
376                         boxed_cnt++;
377                 }
378
379                 /* Count the number of unboxed pages within the given
380                  * generation. */
381                 if (page_table[j].allocated == UNBOXED_PAGE) {
382                     if (page_table[j].large_object)
383                         large_unboxed_cnt++;
384                     else
385                         unboxed_cnt++;
386                 }
387             }
388
389         gc_assert(generations[i].bytes_allocated
390                   == generation_bytes_allocated(i));
391         fprintf(stderr,
392                 "   %8d: %5d %5d %5d %5d %8d %5d %8d %4d %3d %7.4f\n",
393                 i,
394                 boxed_cnt, unboxed_cnt, large_boxed_cnt, large_unboxed_cnt,
395                 generations[i].bytes_allocated,
396                 (count_generation_pages(i)*4096
397                  - generations[i].bytes_allocated),
398                 generations[i].gc_trigger,
399                 count_write_protect_generation_pages(i),
400                 generations[i].num_gc,
401                 gen_av_mem_age(i));
402     }
403     fprintf(stderr,"   Total bytes allocated=%ld\n", bytes_allocated);
404
405     fpu_restore(fpu_state);
406 }
407 \f
408 /*
409  * allocation routines
410  */
411
412 /*
413  * To support quick and inline allocation, regions of memory can be
414  * allocated and then allocated from with just a free pointer and a
415  * check against an end address.
416  *
417  * Since objects can be allocated to spaces with different properties
418  * e.g. boxed/unboxed, generation, ages; there may need to be many
419  * allocation regions.
420  *
421  * Each allocation region may be start within a partly used page. Many
422  * features of memory use are noted on a page wise basis, e.g. the
423  * generation; so if a region starts within an existing allocated page
424  * it must be consistent with this page.
425  *
426  * During the scavenging of the newspace, objects will be transported
427  * into an allocation region, and pointers updated to point to this
428  * allocation region. It is possible that these pointers will be
429  * scavenged again before the allocation region is closed, e.g. due to
430  * trans_list which jumps all over the place to cleanup the list. It
431  * is important to be able to determine properties of all objects
432  * pointed to when scavenging, e.g to detect pointers to the oldspace.
433  * Thus it's important that the allocation regions have the correct
434  * properties set when allocated, and not just set when closed. The
435  * region allocation routines return regions with the specified
436  * properties, and grab all the pages, setting their properties
437  * appropriately, except that the amount used is not known.
438  *
439  * These regions are used to support quicker allocation using just a
440  * free pointer. The actual space used by the region is not reflected
441  * in the pages tables until it is closed. It can't be scavenged until
442  * closed.
443  *
444  * When finished with the region it should be closed, which will
445  * update the page tables for the actual space used returning unused
446  * space. Further it may be noted in the new regions which is
447  * necessary when scavenging the newspace.
448  *
449  * Large objects may be allocated directly without an allocation
450  * region, the page tables are updated immediately.
451  *
452  * Unboxed objects don't contain pointers to other objects and so
453  * don't need scavenging. Further they can't contain pointers to
454  * younger generations so WP is not needed. By allocating pages to
455  * unboxed objects the whole page never needs scavenging or
456  * write-protecting. */
457
458 /* We are only using two regions at present. Both are for the current
459  * newspace generation. */
460 struct alloc_region boxed_region;
461 struct alloc_region unboxed_region;
462
463 /* XX hack. Current Lisp code uses the following. Need copying in/out. */
464 void *current_region_free_pointer;
465 void *current_region_end_addr;
466
467 /* The generation currently being allocated to. */
468 static int gc_alloc_generation;
469
470 /* Find a new region with room for at least the given number of bytes.
471  *
472  * It starts looking at the current generation's alloc_start_page. So
473  * may pick up from the previous region if there is enough space. This
474  * keeps the allocation contiguous when scavenging the newspace.
475  *
476  * The alloc_region should have been closed by a call to
477  * gc_alloc_update_page_tables, and will thus be in an empty state.
478  *
479  * To assist the scavenging functions write-protected pages are not
480  * used. Free pages should not be write-protected.
481  *
482  * It is critical to the conservative GC that the start of regions be
483  * known. To help achieve this only small regions are allocated at a
484  * time.
485  *
486  * During scavenging, pointers may be found to within the current
487  * region and the page generation must be set so that pointers to the
488  * from space can be recognized. Therefore the generation of pages in
489  * the region are set to gc_alloc_generation. To prevent another
490  * allocation call using the same pages, all the pages in the region
491  * are allocated, although they will initially be empty.
492  */
493 static void
494 gc_alloc_new_region(int nbytes, int unboxed, struct alloc_region *alloc_region)
495 {
496     int first_page;
497     int last_page;
498     int region_size;
499     int restart_page;
500     int bytes_found;
501     int num_pages;
502     int i;
503
504     /*
505     FSHOW((stderr,
506            "/alloc_new_region for %d bytes from gen %d\n",
507            nbytes, gc_alloc_generation));
508     */
509
510     /* Check that the region is in a reset state. */
511     gc_assert((alloc_region->first_page == 0)
512               && (alloc_region->last_page == -1)
513               && (alloc_region->free_pointer == alloc_region->end_addr));
514
515     if (unboxed) {
516         restart_page =
517             generations[gc_alloc_generation].alloc_unboxed_start_page;
518     } else {
519         restart_page =
520             generations[gc_alloc_generation].alloc_start_page;
521     }
522
523     /* Search for a contiguous free region of at least nbytes with the
524      * given properties: boxed/unboxed, generation. */
525     do {
526         first_page = restart_page;
527
528         /* First search for a page with at least 32 bytes free, which is
529          * not write-protected, and which is not marked dont_move. */
530         while ((first_page < NUM_PAGES)
531                && (page_table[first_page].allocated != FREE_PAGE) /* not free page */
532                && ((unboxed &&
533                     (page_table[first_page].allocated != UNBOXED_PAGE))
534                    || (!unboxed &&
535                        (page_table[first_page].allocated != BOXED_PAGE))
536                    || (page_table[first_page].large_object != 0)
537                    || (page_table[first_page].gen != gc_alloc_generation)
538                    || (page_table[first_page].bytes_used >= (4096-32))
539                    || (page_table[first_page].write_protected != 0)
540                    || (page_table[first_page].dont_move != 0)))
541             first_page++;
542         /* Check for a failure. */
543         if (first_page >= NUM_PAGES) {
544             fprintf(stderr,
545                     "Argh! gc_alloc_new_region failed on first_page, nbytes=%d.\n",
546                     nbytes);
547             print_generation_stats(1);
548             lose(NULL);
549         }
550
551         gc_assert(page_table[first_page].write_protected == 0);
552
553         /*
554         FSHOW((stderr,
555                "/first_page=%d bytes_used=%d\n",
556                first_page, page_table[first_page].bytes_used));
557         */
558
559         /* Now search forward to calculate the available region size. It
560          * tries to keeps going until nbytes are found and the number of
561          * pages is greater than some level. This helps keep down the
562          * number of pages in a region. */
563         last_page = first_page;
564         bytes_found = 4096 - page_table[first_page].bytes_used;
565         num_pages = 1;
566         while (((bytes_found < nbytes) || (num_pages < 2))
567                && (last_page < (NUM_PAGES-1))
568                && (page_table[last_page+1].allocated == FREE_PAGE)) {
569             last_page++;
570             num_pages++;
571             bytes_found += 4096;
572             gc_assert(page_table[last_page].write_protected == 0);
573         }
574
575         region_size = (4096 - page_table[first_page].bytes_used)
576             + 4096*(last_page-first_page);
577
578         gc_assert(bytes_found == region_size);
579
580         /*
581         FSHOW((stderr,
582                "/last_page=%d bytes_found=%d num_pages=%d\n",
583                last_page, bytes_found, num_pages));
584         */
585
586         restart_page = last_page + 1;
587     } while ((restart_page < NUM_PAGES) && (bytes_found < nbytes));
588
589     /* Check for a failure. */
590     if ((restart_page >= NUM_PAGES) && (bytes_found < nbytes)) {
591         fprintf(stderr,
592                 "Argh! gc_alloc_new_region failed on restart_page, nbytes=%d.\n",
593                 nbytes);
594         print_generation_stats(1);
595         lose(NULL);
596     }
597
598     /*
599     FSHOW((stderr,
600            "/gc_alloc_new_region gen %d: %d bytes: pages %d to %d: addr=%x\n",
601            gc_alloc_generation,
602            bytes_found,
603            first_page,
604            last_page,
605            page_address(first_page)));
606     */
607
608     /* Set up the alloc_region. */
609     alloc_region->first_page = first_page;
610     alloc_region->last_page = last_page;
611     alloc_region->start_addr = page_table[first_page].bytes_used
612         + page_address(first_page);
613     alloc_region->free_pointer = alloc_region->start_addr;
614     alloc_region->end_addr = alloc_region->start_addr + bytes_found;
615
616     if (gencgc_zero_check) {
617         int *p;
618         for (p = (int *)alloc_region->start_addr;
619             p < (int *)alloc_region->end_addr; p++) {
620             if (*p != 0) {
621                 /* KLUDGE: It would be nice to use %lx and explicit casts
622                  * (long) in code like this, so that it is less likely to
623                  * break randomly when running on a machine with different
624                  * word sizes. -- WHN 19991129 */
625                 lose("The new region at %x is not zero.", p);
626             }
627         }
628     }
629
630     /* Set up the pages. */
631
632     /* The first page may have already been in use. */
633     if (page_table[first_page].bytes_used == 0) {
634         if (unboxed)
635             page_table[first_page].allocated = UNBOXED_PAGE;
636         else
637             page_table[first_page].allocated = BOXED_PAGE;
638         page_table[first_page].gen = gc_alloc_generation;
639         page_table[first_page].large_object = 0;
640         page_table[first_page].first_object_offset = 0;
641     }
642
643     if (unboxed)
644         gc_assert(page_table[first_page].allocated == UNBOXED_PAGE);
645     else
646         gc_assert(page_table[first_page].allocated == BOXED_PAGE);
647     gc_assert(page_table[first_page].gen == gc_alloc_generation);
648     gc_assert(page_table[first_page].large_object == 0);
649
650     for (i = first_page+1; i <= last_page; i++) {
651         if (unboxed)
652             page_table[i].allocated = UNBOXED_PAGE;
653         else
654             page_table[i].allocated = BOXED_PAGE;
655         page_table[i].gen = gc_alloc_generation;
656         page_table[i].large_object = 0;
657         /* This may not be necessary for unboxed regions (think it was
658          * broken before!) */
659         page_table[i].first_object_offset =
660             alloc_region->start_addr - page_address(i);
661     }
662
663     /* Bump up last_free_page. */
664     if (last_page+1 > last_free_page) {
665         last_free_page = last_page+1;
666         SetSymbolValue(ALLOCATION_POINTER,
667                        (lispobj)(((char *)heap_base) + last_free_page*4096));
668         if (last_page+1 > last_used_page)
669             last_used_page = last_page+1;
670     }
671 }
672
673 /* If the record_new_objects flag is 2 then all new regions created
674  * are recorded.
675  *
676  * If it's 1 then then it is only recorded if the first page of the
677  * current region is <= new_areas_ignore_page. This helps avoid
678  * unnecessary recording when doing full scavenge pass.
679  *
680  * The new_object structure holds the page, byte offset, and size of
681  * new regions of objects. Each new area is placed in the array of
682  * these structures pointer to by new_areas. new_areas_index holds the
683  * offset into new_areas.
684  *
685  * If new_area overflows NUM_NEW_AREAS then it stops adding them. The
686  * later code must detect this and handle it, probably by doing a full
687  * scavenge of a generation. */
688 #define NUM_NEW_AREAS 512
689 static int record_new_objects = 0;
690 static int new_areas_ignore_page;
691 struct new_area {
692     int  page;
693     int  offset;
694     int  size;
695 };
696 static struct new_area (*new_areas)[];
697 static int new_areas_index;
698 int max_new_areas;
699
700 /* Add a new area to new_areas. */
701 static void
702 add_new_area(int first_page, int offset, int size)
703 {
704     unsigned new_area_start,c;
705     int i;
706
707     /* Ignore if full. */
708     if (new_areas_index >= NUM_NEW_AREAS)
709         return;
710
711     switch (record_new_objects) {
712     case 0:
713         return;
714     case 1:
715         if (first_page > new_areas_ignore_page)
716             return;
717         break;
718     case 2:
719         break;
720     default:
721         gc_abort();
722     }
723
724     new_area_start = 4096*first_page + offset;
725
726     /* Search backwards for a prior area that this follows from. If
727        found this will save adding a new area. */
728     for (i = new_areas_index-1, c = 0; (i >= 0) && (c < 8); i--, c++) {
729         unsigned area_end =
730             4096*((*new_areas)[i].page)
731             + (*new_areas)[i].offset
732             + (*new_areas)[i].size;
733         /*FSHOW((stderr,
734                "/add_new_area S1 %d %d %d %d\n",
735                i, c, new_area_start, area_end));*/
736         if (new_area_start == area_end) {
737             /*FSHOW((stderr,
738                    "/adding to [%d] %d %d %d with %d %d %d:\n",
739                    i,
740                    (*new_areas)[i].page,
741                    (*new_areas)[i].offset,
742                    (*new_areas)[i].size,
743                    first_page,
744                    offset,
745                    size));*/
746             (*new_areas)[i].size += size;
747             return;
748         }
749     }
750     /*FSHOW((stderr, "/add_new_area S1 %d %d %d\n", i, c, new_area_start));*/
751
752     (*new_areas)[new_areas_index].page = first_page;
753     (*new_areas)[new_areas_index].offset = offset;
754     (*new_areas)[new_areas_index].size = size;
755     /*FSHOW((stderr,
756            "/new_area %d page %d offset %d size %d\n",
757            new_areas_index, first_page, offset, size));*/
758     new_areas_index++;
759
760     /* Note the max new_areas used. */
761     if (new_areas_index > max_new_areas)
762         max_new_areas = new_areas_index;
763 }
764
765 /* Update the tables for the alloc_region. The region maybe added to
766  * the new_areas.
767  *
768  * When done the alloc_region is set up so that the next quick alloc
769  * will fail safely and thus a new region will be allocated. Further
770  * it is safe to try to re-update the page table of this reset
771  * alloc_region. */
772 void
773 gc_alloc_update_page_tables(int unboxed, struct alloc_region *alloc_region)
774 {
775     int more;
776     int first_page;
777     int next_page;
778     int bytes_used;
779     int orig_first_page_bytes_used;
780     int region_size;
781     int byte_cnt;
782
783     /*
784     FSHOW((stderr,
785            "/gc_alloc_update_page_tables to gen %d:\n",
786            gc_alloc_generation));
787     */
788
789     first_page = alloc_region->first_page;
790
791     /* Catch an unused alloc_region. */
792     if ((first_page == 0) && (alloc_region->last_page == -1))
793         return;
794
795     next_page = first_page+1;
796
797     /* Skip if no bytes were allocated */
798     if (alloc_region->free_pointer != alloc_region->start_addr) {
799         orig_first_page_bytes_used = page_table[first_page].bytes_used;
800
801         gc_assert(alloc_region->start_addr == (page_address(first_page) + page_table[first_page].bytes_used));
802
803         /* All the pages used need to be updated */
804
805         /* Update the first page. */
806
807         /* If the page was free then set up the gen, and
808            first_object_offset. */
809         if (page_table[first_page].bytes_used == 0)
810             gc_assert(page_table[first_page].first_object_offset == 0);
811
812         if (unboxed)
813             gc_assert(page_table[first_page].allocated == UNBOXED_PAGE);
814         else
815             gc_assert(page_table[first_page].allocated == BOXED_PAGE);
816         gc_assert(page_table[first_page].gen == gc_alloc_generation);
817         gc_assert(page_table[first_page].large_object == 0);
818
819         byte_cnt = 0;
820
821         /* Calc. the number of bytes used in this page. This is not always
822            the number of new bytes, unless it was free. */
823         more = 0;
824         if ((bytes_used = (alloc_region->free_pointer - page_address(first_page)))>4096) {
825             bytes_used = 4096;
826             more = 1;
827         }
828         page_table[first_page].bytes_used = bytes_used;
829         byte_cnt += bytes_used;
830
831
832         /* All the rest of the pages should be free. Need to set their
833            first_object_offset pointer to the start of the region, and set
834            the bytes_used. */
835         while (more) {
836             if (unboxed)
837                 gc_assert(page_table[next_page].allocated == UNBOXED_PAGE);
838             else
839                 gc_assert(page_table[next_page].allocated == BOXED_PAGE);
840             gc_assert(page_table[next_page].bytes_used == 0);
841             gc_assert(page_table[next_page].gen == gc_alloc_generation);
842             gc_assert(page_table[next_page].large_object == 0);
843
844             gc_assert(page_table[next_page].first_object_offset ==
845                       alloc_region->start_addr - page_address(next_page));
846
847             /* Calculate the number of bytes used in this page. */
848             more = 0;
849             if ((bytes_used = (alloc_region->free_pointer
850                                - page_address(next_page)))>4096) {
851                 bytes_used = 4096;
852                 more = 1;
853             }
854             page_table[next_page].bytes_used = bytes_used;
855             byte_cnt += bytes_used;
856
857             next_page++;
858         }
859
860         region_size = alloc_region->free_pointer - alloc_region->start_addr;
861         bytes_allocated += region_size;
862         generations[gc_alloc_generation].bytes_allocated += region_size;
863
864         gc_assert((byte_cnt- orig_first_page_bytes_used) == region_size);
865
866         /* Set the generations alloc restart page to the last page of
867            the region. */
868         if (unboxed)
869             generations[gc_alloc_generation].alloc_unboxed_start_page =
870                 next_page-1;
871         else
872             generations[gc_alloc_generation].alloc_start_page = next_page-1;
873
874         /* Add the region to the new_areas if requested. */
875         if (!unboxed)
876             add_new_area(first_page,orig_first_page_bytes_used, region_size);
877
878         /*
879         FSHOW((stderr,
880                "/gc_alloc_update_page_tables update %d bytes to gen %d\n",
881                region_size,
882                gc_alloc_generation));
883         */
884     }
885     else
886         /* No bytes allocated. Unallocate the first_page if there are 0
887            bytes_used. */
888         if (page_table[first_page].bytes_used == 0)
889             page_table[first_page].allocated = FREE_PAGE;
890
891     /* Unallocate any unused pages. */
892     while (next_page <= alloc_region->last_page) {
893         gc_assert(page_table[next_page].bytes_used == 0);
894         page_table[next_page].allocated = FREE_PAGE;
895         next_page++;
896     }
897
898     /* Reset the alloc_region. */
899     alloc_region->first_page = 0;
900     alloc_region->last_page = -1;
901     alloc_region->start_addr = page_address(0);
902     alloc_region->free_pointer = page_address(0);
903     alloc_region->end_addr = page_address(0);
904 }
905
906 static inline void *gc_quick_alloc(int nbytes);
907
908 /* Allocate a possibly large object. */
909 static void
910 *gc_alloc_large(int nbytes, int unboxed, struct alloc_region *alloc_region)
911 {
912     int first_page;
913     int last_page;
914     int region_size;
915     int restart_page;
916     int bytes_found;
917     int num_pages;
918     int orig_first_page_bytes_used;
919     int byte_cnt;
920     int more;
921     int bytes_used;
922     int next_page;
923     int large = (nbytes >= large_object_size);
924
925     /*
926     if (nbytes > 200000)
927         FSHOW((stderr, "/alloc_large %d\n", nbytes));
928     */
929
930     /*
931     FSHOW((stderr,
932            "/gc_alloc_large for %d bytes from gen %d\n",
933            nbytes, gc_alloc_generation));
934     */
935
936     /* If the object is small, and there is room in the current region
937        then allocation it in the current region. */
938     if (!large
939         && ((alloc_region->end_addr-alloc_region->free_pointer) >= nbytes))
940         return gc_quick_alloc(nbytes);
941
942     /* Search for a contiguous free region of at least nbytes. If it's a
943        large object then align it on a page boundary by searching for a
944        free page. */
945
946     /* To allow the allocation of small objects without the danger of
947        using a page in the current boxed region, the search starts after
948        the current boxed free region. XX could probably keep a page
949        index ahead of the current region and bumped up here to save a
950        lot of re-scanning. */
951     if (unboxed)
952         restart_page = generations[gc_alloc_generation].alloc_large_unboxed_start_page;
953     else
954         restart_page = generations[gc_alloc_generation].alloc_large_start_page;
955     if (restart_page <= alloc_region->last_page)
956         restart_page = alloc_region->last_page+1;
957
958     do {
959         first_page = restart_page;
960
961         if (large)
962             while ((first_page < NUM_PAGES)
963                    && (page_table[first_page].allocated != FREE_PAGE))
964                 first_page++;
965         else
966             while ((first_page < NUM_PAGES)
967                    && (page_table[first_page].allocated != FREE_PAGE)
968                    && ((unboxed &&
969                         (page_table[first_page].allocated != UNBOXED_PAGE))
970                        || (!unboxed &&
971                            (page_table[first_page].allocated != BOXED_PAGE))
972                        || (page_table[first_page].large_object != 0)
973                        || (page_table[first_page].gen != gc_alloc_generation)
974                        || (page_table[first_page].bytes_used >= (4096-32))
975                        || (page_table[first_page].write_protected != 0)
976                        || (page_table[first_page].dont_move != 0)))
977                 first_page++;
978
979         if (first_page >= NUM_PAGES) {
980             fprintf(stderr,
981                     "Argh! gc_alloc_large failed (first_page), nbytes=%d.\n",
982                     nbytes);
983             print_generation_stats(1);
984             lose(NULL);
985         }
986
987         gc_assert(page_table[first_page].write_protected == 0);
988
989         /*
990         FSHOW((stderr,
991                "/first_page=%d bytes_used=%d\n",
992                first_page, page_table[first_page].bytes_used));
993         */
994
995         last_page = first_page;
996         bytes_found = 4096 - page_table[first_page].bytes_used;
997         num_pages = 1;
998         while ((bytes_found < nbytes)
999                && (last_page < (NUM_PAGES-1))
1000                && (page_table[last_page+1].allocated == FREE_PAGE)) {
1001             last_page++;
1002             num_pages++;
1003             bytes_found += 4096;
1004             gc_assert(page_table[last_page].write_protected == 0);
1005         }
1006
1007         region_size = (4096 - page_table[first_page].bytes_used)
1008             + 4096*(last_page-first_page);
1009
1010         gc_assert(bytes_found == region_size);
1011
1012         /*
1013         FSHOW((stderr,
1014                "/last_page=%d bytes_found=%d num_pages=%d\n",
1015                last_page, bytes_found, num_pages));
1016         */
1017
1018         restart_page = last_page + 1;
1019     } while ((restart_page < NUM_PAGES) && (bytes_found < nbytes));
1020
1021     /* Check for a failure */
1022     if ((restart_page >= NUM_PAGES) && (bytes_found < nbytes)) {
1023         fprintf(stderr,
1024                 "Argh! gc_alloc_large failed (restart_page), nbytes=%d.\n",
1025                 nbytes);
1026         print_generation_stats(1);
1027         lose(NULL);
1028     }
1029
1030     /*
1031     if (large)
1032         FSHOW((stderr,
1033                "/gc_alloc_large gen %d: %d of %d bytes: from pages %d to %d: addr=%x\n",
1034                gc_alloc_generation,
1035                nbytes,
1036                bytes_found,
1037                first_page,
1038                last_page,
1039                page_address(first_page)));
1040     */
1041
1042     gc_assert(first_page > alloc_region->last_page);
1043     if (unboxed)
1044         generations[gc_alloc_generation].alloc_large_unboxed_start_page =
1045             last_page;
1046     else
1047         generations[gc_alloc_generation].alloc_large_start_page = last_page;
1048
1049     /* Set up the pages. */
1050     orig_first_page_bytes_used = page_table[first_page].bytes_used;
1051
1052     /* If the first page was free then set up the gen, and
1053      * first_object_offset. */
1054     if (page_table[first_page].bytes_used == 0) {
1055         if (unboxed)
1056             page_table[first_page].allocated = UNBOXED_PAGE;
1057         else
1058             page_table[first_page].allocated = BOXED_PAGE;
1059         page_table[first_page].gen = gc_alloc_generation;
1060         page_table[first_page].first_object_offset = 0;
1061         page_table[first_page].large_object = large;
1062     }
1063
1064     if (unboxed)
1065         gc_assert(page_table[first_page].allocated == UNBOXED_PAGE);
1066     else
1067         gc_assert(page_table[first_page].allocated == BOXED_PAGE);
1068     gc_assert(page_table[first_page].gen == gc_alloc_generation);
1069     gc_assert(page_table[first_page].large_object == large);
1070
1071     byte_cnt = 0;
1072
1073     /* Calc. the number of bytes used in this page. This is not
1074      * always the number of new bytes, unless it was free. */
1075     more = 0;
1076     if ((bytes_used = nbytes+orig_first_page_bytes_used) > 4096) {
1077         bytes_used = 4096;
1078         more = 1;
1079     }
1080     page_table[first_page].bytes_used = bytes_used;
1081     byte_cnt += bytes_used;
1082
1083     next_page = first_page+1;
1084
1085     /* All the rest of the pages should be free. We need to set their
1086      * first_object_offset pointer to the start of the region, and
1087      * set the bytes_used. */
1088     while (more) {
1089         gc_assert(page_table[next_page].allocated == FREE_PAGE);
1090         gc_assert(page_table[next_page].bytes_used == 0);
1091         if (unboxed)
1092             page_table[next_page].allocated = UNBOXED_PAGE;
1093         else
1094             page_table[next_page].allocated = BOXED_PAGE;
1095         page_table[next_page].gen = gc_alloc_generation;
1096         page_table[next_page].large_object = large;
1097
1098         page_table[next_page].first_object_offset =
1099             orig_first_page_bytes_used - 4096*(next_page-first_page);
1100
1101         /* Calculate the number of bytes used in this page. */
1102         more = 0;
1103         if ((bytes_used=(nbytes+orig_first_page_bytes_used)-byte_cnt) > 4096) {
1104             bytes_used = 4096;
1105             more = 1;
1106         }
1107         page_table[next_page].bytes_used = bytes_used;
1108         byte_cnt += bytes_used;
1109
1110         next_page++;
1111     }
1112
1113     gc_assert((byte_cnt-orig_first_page_bytes_used) == nbytes);
1114
1115     bytes_allocated += nbytes;
1116     generations[gc_alloc_generation].bytes_allocated += nbytes;
1117
1118     /* Add the region to the new_areas if requested. */
1119     if (!unboxed)
1120         add_new_area(first_page,orig_first_page_bytes_used,nbytes);
1121
1122     /* Bump up last_free_page */
1123     if (last_page+1 > last_free_page) {
1124         last_free_page = last_page+1;
1125         SetSymbolValue(ALLOCATION_POINTER,
1126                        (lispobj)(((char *)heap_base) + last_free_page*4096));
1127         if (last_page+1 > last_used_page)
1128             last_used_page = last_page+1;
1129     }
1130
1131     return((void *)(page_address(first_page)+orig_first_page_bytes_used));
1132 }
1133
1134 /* Allocate bytes from the boxed_region. It first checks if there is
1135  * room, if not then it calls gc_alloc_new_region to find a new region
1136  * with enough space. A pointer to the start of the region is returned. */
1137 static void
1138 *gc_alloc(int nbytes)
1139 {
1140     void *new_free_pointer;
1141
1142     /* FSHOW((stderr, "/gc_alloc %d\n", nbytes)); */
1143
1144     /* Check whether there is room in the current alloc region. */
1145     new_free_pointer = boxed_region.free_pointer + nbytes;
1146
1147     if (new_free_pointer <= boxed_region.end_addr) {
1148         /* If so then allocate from the current alloc region. */
1149         void *new_obj = boxed_region.free_pointer;
1150         boxed_region.free_pointer = new_free_pointer;
1151
1152         /* Check whether the alloc region is almost empty. */
1153         if ((boxed_region.end_addr - boxed_region.free_pointer) <= 32) {
1154             /* If so finished with the current region. */
1155             gc_alloc_update_page_tables(0, &boxed_region);
1156             /* Set up a new region. */
1157             gc_alloc_new_region(32, 0, &boxed_region);
1158         }
1159         return((void *)new_obj);
1160     }
1161
1162     /* Else not enough free space in the current region. */
1163
1164     /* If there some room left in the current region, enough to be worth
1165      * saving, then allocate a large object. */
1166     /* FIXME: "32" should be a named parameter. */
1167     if ((boxed_region.end_addr-boxed_region.free_pointer) > 32)
1168         return gc_alloc_large(nbytes, 0, &boxed_region);
1169
1170     /* Else find a new region. */
1171
1172     /* Finished with the current region. */
1173     gc_alloc_update_page_tables(0, &boxed_region);
1174
1175     /* Set up a new region. */
1176     gc_alloc_new_region(nbytes, 0, &boxed_region);
1177
1178     /* Should now be enough room. */
1179
1180     /* Check whether there is room in the current region. */
1181     new_free_pointer = boxed_region.free_pointer + nbytes;
1182
1183     if (new_free_pointer <= boxed_region.end_addr) {
1184         /* If so then allocate from the current region. */
1185         void *new_obj = boxed_region.free_pointer;
1186         boxed_region.free_pointer = new_free_pointer;
1187
1188         /* Check whether the current region is almost empty. */
1189         if ((boxed_region.end_addr - boxed_region.free_pointer) <= 32) {
1190             /* If so find, finished with the current region. */
1191             gc_alloc_update_page_tables(0, &boxed_region);
1192
1193             /* Set up a new region. */
1194             gc_alloc_new_region(32, 0, &boxed_region);
1195         }
1196
1197         return((void *)new_obj);
1198     }
1199
1200     /* shouldn't happen */
1201     gc_assert(0);
1202     return((void *) NIL); /* dummy value: return something ... */
1203 }
1204
1205 /* Allocate space from the boxed_region. If there is not enough free
1206  * space then call gc_alloc to do the job. A pointer to the start of
1207  * the region is returned. */
1208 static inline void
1209 *gc_quick_alloc(int nbytes)
1210 {
1211     void *new_free_pointer;
1212
1213     /* Check whether there is room in the current region. */
1214     new_free_pointer = boxed_region.free_pointer + nbytes;
1215
1216     if (new_free_pointer <= boxed_region.end_addr) {
1217         /* If so then allocate from the current region. */
1218         void  *new_obj = boxed_region.free_pointer;
1219         boxed_region.free_pointer = new_free_pointer;
1220         return((void *)new_obj);
1221     }
1222
1223     /* Else call gc_alloc */
1224     return (gc_alloc(nbytes));
1225 }
1226
1227 /* Allocate space for the boxed object. If it is a large object then
1228  * do a large alloc else allocate from the current region. If there is
1229  * not enough free space then call gc_alloc to do the job. A pointer
1230  * to the start of the region is returned. */
1231 static inline void
1232 *gc_quick_alloc_large(int nbytes)
1233 {
1234     void *new_free_pointer;
1235
1236     if (nbytes >= large_object_size)
1237         return gc_alloc_large(nbytes, 0, &boxed_region);
1238
1239     /* Check whether there is room in the current region. */
1240     new_free_pointer = boxed_region.free_pointer + nbytes;
1241
1242     if (new_free_pointer <= boxed_region.end_addr) {
1243         /* If so then allocate from the current region. */
1244         void *new_obj = boxed_region.free_pointer;
1245         boxed_region.free_pointer = new_free_pointer;
1246         return((void *)new_obj);
1247     }
1248
1249     /* Else call gc_alloc */
1250     return (gc_alloc(nbytes));
1251 }
1252
1253 static void
1254 *gc_alloc_unboxed(int nbytes)
1255 {
1256     void *new_free_pointer;
1257
1258     /*
1259     FSHOW((stderr, "/gc_alloc_unboxed %d\n", nbytes));
1260     */
1261
1262     /* Check whether there is room in the current region. */
1263     new_free_pointer = unboxed_region.free_pointer + nbytes;
1264
1265     if (new_free_pointer <= unboxed_region.end_addr) {
1266         /* If so then allocate from the current region. */
1267         void *new_obj = unboxed_region.free_pointer;
1268         unboxed_region.free_pointer = new_free_pointer;
1269
1270         /* Check whether the current region is almost empty. */
1271         if ((unboxed_region.end_addr - unboxed_region.free_pointer) <= 32) {
1272             /* If so finished with the current region. */
1273             gc_alloc_update_page_tables(1, &unboxed_region);
1274
1275             /* Set up a new region. */
1276             gc_alloc_new_region(32, 1, &unboxed_region);
1277         }
1278
1279         return((void *)new_obj);
1280     }
1281
1282     /* Else not enough free space in the current region. */
1283
1284     /* If there is a bit of room left in the current region then
1285        allocate a large object. */
1286     if ((unboxed_region.end_addr-unboxed_region.free_pointer) > 32)
1287         return gc_alloc_large(nbytes,1,&unboxed_region);
1288
1289     /* Else find a new region. */
1290
1291     /* Finished with the current region. */
1292     gc_alloc_update_page_tables(1, &unboxed_region);
1293
1294     /* Set up a new region. */
1295     gc_alloc_new_region(nbytes, 1, &unboxed_region);
1296
1297     /* Should now be enough room. */
1298
1299     /* Check whether there is room in the current region. */
1300     new_free_pointer = unboxed_region.free_pointer + nbytes;
1301
1302     if (new_free_pointer <= unboxed_region.end_addr) {
1303         /* If so then allocate from the current region. */
1304         void *new_obj = unboxed_region.free_pointer;
1305         unboxed_region.free_pointer = new_free_pointer;
1306
1307         /* Check whether the current region is almost empty. */
1308         if ((unboxed_region.end_addr - unboxed_region.free_pointer) <= 32) {
1309             /* If so find, finished with the current region. */
1310             gc_alloc_update_page_tables(1, &unboxed_region);
1311
1312             /* Set up a new region. */
1313             gc_alloc_new_region(32, 1, &unboxed_region);
1314         }
1315
1316         return((void *)new_obj);
1317     }
1318
1319     /* shouldn't happen? */
1320     gc_assert(0);
1321     return((void *) NIL); /* dummy value: return something ... */
1322 }
1323
1324 static inline void
1325 *gc_quick_alloc_unboxed(int nbytes)
1326 {
1327     void *new_free_pointer;
1328
1329     /* Check whether there is room in the current region. */
1330     new_free_pointer = unboxed_region.free_pointer + nbytes;
1331
1332     if (new_free_pointer <= unboxed_region.end_addr) {
1333         /* If so then allocate from the current region. */
1334         void *new_obj = unboxed_region.free_pointer;
1335         unboxed_region.free_pointer = new_free_pointer;
1336
1337         return((void *)new_obj);
1338     }
1339
1340     /* Else call gc_alloc */
1341     return (gc_alloc_unboxed(nbytes));
1342 }
1343
1344 /* Allocate space for the object. If it is a large object then do a
1345  * large alloc else allocate from the current region. If there is not
1346  * enough free space then call gc_alloc to do the job.
1347  *
1348  * A pointer to the start of the region is returned. */
1349 static inline void
1350 *gc_quick_alloc_large_unboxed(int nbytes)
1351 {
1352     void *new_free_pointer;
1353
1354     if (nbytes >= large_object_size)
1355         return gc_alloc_large(nbytes,1,&unboxed_region);
1356
1357     /* Check whether there is room in the current region. */
1358     new_free_pointer = unboxed_region.free_pointer + nbytes;
1359
1360     if (new_free_pointer <= unboxed_region.end_addr) {
1361         /* If so then allocate from the current region. */
1362         void *new_obj = unboxed_region.free_pointer;
1363         unboxed_region.free_pointer = new_free_pointer;
1364
1365         return((void *)new_obj);
1366     }
1367
1368     /* Else call gc_alloc. */
1369     return (gc_alloc_unboxed(nbytes));
1370 }
1371 \f
1372 /*
1373  * scavenging/transporting routines derived from gc.c in CMU CL ca. 18b
1374  */
1375
1376 static int (*scavtab[256])(lispobj *where, lispobj object);
1377 static lispobj (*transother[256])(lispobj object);
1378 static int (*sizetab[256])(lispobj *where);
1379
1380 static struct weak_pointer *weak_pointers;
1381
1382 #define CEILING(x,y) (((x) + ((y) - 1)) & (~((y) - 1)))
1383 \f
1384 /*
1385  * predicates
1386  */
1387
1388 static inline boolean
1389 from_space_p(lispobj obj)
1390 {
1391     int page_index=(void*)obj - heap_base;
1392     return ((page_index >= 0)
1393             && ((page_index = ((unsigned int)page_index)/4096) < NUM_PAGES)
1394             && (page_table[page_index].gen == from_space));
1395 }
1396
1397 static inline boolean
1398 new_space_p(lispobj obj)
1399 {
1400     int page_index = (void*)obj - heap_base;
1401     return ((page_index >= 0)
1402             && ((page_index = ((unsigned int)page_index)/4096) < NUM_PAGES)
1403             && (page_table[page_index].gen == new_space));
1404 }
1405 \f
1406 /*
1407  * copying objects
1408  */
1409
1410 /* to copy a boxed object */
1411 static inline lispobj
1412 copy_object(lispobj object, int nwords)
1413 {
1414     int tag;
1415     lispobj *new;
1416     lispobj *source, *dest;
1417
1418     gc_assert(Pointerp(object));
1419     gc_assert(from_space_p(object));
1420     gc_assert((nwords & 0x01) == 0);
1421
1422     /* Get tag of object. */
1423     tag = LowtagOf(object);
1424
1425     /* Allocate space. */
1426     new = gc_quick_alloc(nwords*4);
1427
1428     dest = new;
1429     source = (lispobj *) PTR(object);
1430
1431     /* Copy the object. */
1432     while (nwords > 0) {
1433         dest[0] = source[0];
1434         dest[1] = source[1];
1435         dest += 2;
1436         source += 2;
1437         nwords -= 2;
1438     }
1439
1440     /* Return Lisp pointer of new object. */
1441     return ((lispobj) new) | tag;
1442 }
1443
1444 /* to copy a large boxed object. If the object is in a large object
1445  * region then it is simply promoted, else it is copied. If it's large
1446  * enough then it's copied to a large object region.
1447  *
1448  * Vectors may have shrunk. If the object is not copied the space
1449  * needs to be reclaimed, and the page_tables corrected. */
1450 static lispobj
1451 copy_large_object(lispobj object, int nwords)
1452 {
1453     int tag;
1454     lispobj *new;
1455     lispobj *source, *dest;
1456     int first_page;
1457
1458     gc_assert(Pointerp(object));
1459     gc_assert(from_space_p(object));
1460     gc_assert((nwords & 0x01) == 0);
1461
1462     if ((nwords > 1024*1024) && gencgc_verbose) {
1463         FSHOW((stderr, "/copy_large_object: %d bytes\n", nwords*4));
1464     }
1465
1466     /* Check whether it's a large object. */
1467     first_page = find_page_index((void *)object);
1468     gc_assert(first_page >= 0);
1469
1470     if (page_table[first_page].large_object) {
1471
1472         /* Promote the object. */
1473
1474         int remaining_bytes;
1475         int next_page;
1476         int bytes_freed;
1477         int old_bytes_used;
1478
1479         /* Note: Any page write-protection must be removed, else a
1480          * later scavenge_newspace may incorrectly not scavenge these
1481          * pages. This would not be necessary if they are added to the
1482          * new areas, but let's do it for them all (they'll probably
1483          * be written anyway?). */
1484
1485         gc_assert(page_table[first_page].first_object_offset == 0);
1486
1487         next_page = first_page;
1488         remaining_bytes = nwords*4;
1489         while (remaining_bytes > 4096) {
1490             gc_assert(page_table[next_page].gen == from_space);
1491             gc_assert(page_table[next_page].allocated == BOXED_PAGE);
1492             gc_assert(page_table[next_page].large_object);
1493             gc_assert(page_table[next_page].first_object_offset==
1494                       -4096*(next_page-first_page));
1495             gc_assert(page_table[next_page].bytes_used == 4096);
1496
1497             page_table[next_page].gen = new_space;
1498
1499             /* Remove any write-protection. We should be able to rely
1500              * on the write-protect flag to avoid redundant calls. */
1501             if (page_table[next_page].write_protected) {
1502                 os_protect(page_address(next_page), 4096, OS_VM_PROT_ALL);
1503                 page_table[next_page].write_protected = 0;
1504             }
1505             remaining_bytes -= 4096;
1506             next_page++;
1507         }
1508
1509         /* Now only one page remains, but the object may have shrunk
1510          * so there may be more unused pages which will be freed. */
1511
1512         /* The object may have shrunk but shouldn't have grown. */
1513         gc_assert(page_table[next_page].bytes_used >= remaining_bytes);
1514
1515         page_table[next_page].gen = new_space;
1516         gc_assert(page_table[next_page].allocated = BOXED_PAGE);
1517
1518         /* Adjust the bytes_used. */
1519         old_bytes_used = page_table[next_page].bytes_used;
1520         page_table[next_page].bytes_used = remaining_bytes;
1521
1522         bytes_freed = old_bytes_used - remaining_bytes;
1523
1524         /* Free any remaining pages; needs care. */
1525         next_page++;
1526         while ((old_bytes_used == 4096) &&
1527                (page_table[next_page].gen == from_space) &&
1528                (page_table[next_page].allocated == BOXED_PAGE) &&
1529                page_table[next_page].large_object &&
1530                (page_table[next_page].first_object_offset ==
1531                 -(next_page - first_page)*4096)) {
1532             /* Checks out OK, free the page. Don't need to both zeroing
1533              * pages as this should have been done before shrinking the
1534              * object. These pages shouldn't be write-protected as they
1535              * should be zero filled. */
1536             gc_assert(page_table[next_page].write_protected == 0);
1537
1538             old_bytes_used = page_table[next_page].bytes_used;
1539             page_table[next_page].allocated = FREE_PAGE;
1540             page_table[next_page].bytes_used = 0;
1541             bytes_freed += old_bytes_used;
1542             next_page++;
1543         }
1544
1545         if ((bytes_freed > 0) && gencgc_verbose)
1546             FSHOW((stderr, "/copy_large_boxed bytes_freed=%d\n", bytes_freed));
1547
1548         generations[from_space].bytes_allocated -= 4*nwords + bytes_freed;
1549         generations[new_space].bytes_allocated += 4*nwords;
1550         bytes_allocated -= bytes_freed;
1551
1552         /* Add the region to the new_areas if requested. */
1553         add_new_area(first_page,0,nwords*4);
1554
1555         return(object);
1556     } else {
1557         /* Get tag of object. */
1558         tag = LowtagOf(object);
1559
1560         /* Allocate space. */
1561         new = gc_quick_alloc_large(nwords*4);
1562
1563         dest = new;
1564         source = (lispobj *) PTR(object);
1565
1566         /* Copy the object. */
1567         while (nwords > 0) {
1568             dest[0] = source[0];
1569             dest[1] = source[1];
1570             dest += 2;
1571             source += 2;
1572             nwords -= 2;
1573         }
1574
1575         /* Return Lisp pointer of new object. */
1576         return ((lispobj) new) | tag;
1577     }
1578 }
1579
1580 /* to copy unboxed objects */
1581 static inline lispobj
1582 copy_unboxed_object(lispobj object, int nwords)
1583 {
1584     int tag;
1585     lispobj *new;
1586     lispobj *source, *dest;
1587
1588     gc_assert(Pointerp(object));
1589     gc_assert(from_space_p(object));
1590     gc_assert((nwords & 0x01) == 0);
1591
1592     /* Get tag of object. */
1593     tag = LowtagOf(object);
1594
1595     /* Allocate space. */
1596     new = gc_quick_alloc_unboxed(nwords*4);
1597
1598     dest = new;
1599     source = (lispobj *) PTR(object);
1600
1601     /* Copy the object. */
1602     while (nwords > 0) {
1603         dest[0] = source[0];
1604         dest[1] = source[1];
1605         dest += 2;
1606         source += 2;
1607         nwords -= 2;
1608     }
1609
1610     /* Return Lisp pointer of new object. */
1611     return ((lispobj) new) | tag;
1612 }
1613
1614 /* to copy large unboxed objects
1615  *
1616  * If the object is in a large object region then it is simply
1617  * promoted, else it is copied. If it's large enough then it's copied
1618  * to a large object region.
1619  *
1620  * Bignums and vectors may have shrunk. If the object is not copied
1621  * the space needs to be reclaimed, and the page_tables corrected.
1622  *
1623  * KLUDGE: There's a lot of cut-and-paste duplication between this
1624  * function and copy_large_object(..). -- WHN 20000619 */
1625 static lispobj
1626 copy_large_unboxed_object(lispobj object, int nwords)
1627 {
1628     int tag;
1629     lispobj *new;
1630     lispobj *source, *dest;
1631     int first_page;
1632
1633     gc_assert(Pointerp(object));
1634     gc_assert(from_space_p(object));
1635     gc_assert((nwords & 0x01) == 0);
1636
1637     if ((nwords > 1024*1024) && gencgc_verbose)
1638         FSHOW((stderr, "/copy_large_unboxed_object: %d bytes\n", nwords*4));
1639
1640     /* Check whether it's a large object. */
1641     first_page = find_page_index((void *)object);
1642     gc_assert(first_page >= 0);
1643
1644     if (page_table[first_page].large_object) {
1645         /* Promote the object. Note: Unboxed objects may have been
1646          * allocated to a BOXED region so it may be necessary to
1647          * change the region to UNBOXED. */
1648         int remaining_bytes;
1649         int next_page;
1650         int bytes_freed;
1651         int old_bytes_used;
1652
1653         gc_assert(page_table[first_page].first_object_offset == 0);
1654
1655         next_page = first_page;
1656         remaining_bytes = nwords*4;
1657         while (remaining_bytes > 4096) {
1658             gc_assert(page_table[next_page].gen == from_space);
1659             gc_assert((page_table[next_page].allocated == UNBOXED_PAGE)
1660                       || (page_table[next_page].allocated == BOXED_PAGE));
1661             gc_assert(page_table[next_page].large_object);
1662             gc_assert(page_table[next_page].first_object_offset==
1663                       -4096*(next_page-first_page));
1664             gc_assert(page_table[next_page].bytes_used == 4096);
1665
1666             page_table[next_page].gen = new_space;
1667             page_table[next_page].allocated = UNBOXED_PAGE;
1668             remaining_bytes -= 4096;
1669             next_page++;
1670         }
1671
1672         /* Now only one page remains, but the object may have shrunk so
1673          * there may be more unused pages which will be freed. */
1674
1675         /* Object may have shrunk but shouldn't have grown - check. */
1676         gc_assert(page_table[next_page].bytes_used >= remaining_bytes);
1677
1678         page_table[next_page].gen = new_space;
1679         page_table[next_page].allocated = UNBOXED_PAGE;
1680
1681         /* Adjust the bytes_used. */
1682         old_bytes_used = page_table[next_page].bytes_used;
1683         page_table[next_page].bytes_used = remaining_bytes;
1684
1685         bytes_freed = old_bytes_used - remaining_bytes;
1686
1687         /* Free any remaining pages; needs care. */
1688         next_page++;
1689         while ((old_bytes_used == 4096) &&
1690                (page_table[next_page].gen == from_space) &&
1691                ((page_table[next_page].allocated == UNBOXED_PAGE)
1692                 || (page_table[next_page].allocated == BOXED_PAGE)) &&
1693                page_table[next_page].large_object &&
1694                (page_table[next_page].first_object_offset ==
1695                 -(next_page - first_page)*4096)) {
1696             /* Checks out OK, free the page. Don't need to both zeroing
1697              * pages as this should have been done before shrinking the
1698              * object. These pages shouldn't be write-protected, even if
1699              * boxed they should be zero filled. */
1700             gc_assert(page_table[next_page].write_protected == 0);
1701
1702             old_bytes_used = page_table[next_page].bytes_used;
1703             page_table[next_page].allocated = FREE_PAGE;
1704             page_table[next_page].bytes_used = 0;
1705             bytes_freed += old_bytes_used;
1706             next_page++;
1707         }
1708
1709         if ((bytes_freed > 0) && gencgc_verbose)
1710             FSHOW((stderr,
1711                    "/copy_large_unboxed bytes_freed=%d\n",
1712                    bytes_freed));
1713
1714         generations[from_space].bytes_allocated -= 4*nwords + bytes_freed;
1715         generations[new_space].bytes_allocated += 4*nwords;
1716         bytes_allocated -= bytes_freed;
1717
1718         return(object);
1719     }
1720     else {
1721         /* Get tag of object. */
1722         tag = LowtagOf(object);
1723
1724         /* Allocate space. */
1725         new = gc_quick_alloc_large_unboxed(nwords*4);
1726
1727         dest = new;
1728         source = (lispobj *) PTR(object);
1729
1730         /* Copy the object. */
1731         while (nwords > 0) {
1732             dest[0] = source[0];
1733             dest[1] = source[1];
1734             dest += 2;
1735             source += 2;
1736             nwords -= 2;
1737         }
1738
1739         /* Return Lisp pointer of new object. */
1740         return ((lispobj) new) | tag;
1741     }
1742 }
1743 \f
1744 /*
1745  * scavenging
1746  */
1747
1748 /* FIXME: Most calls end up going to some trouble to compute an
1749  * 'n_words' value for this function. The system might be a little
1750  * simpler if this function used an 'end' parameter instead. */
1751 static void
1752 scavenge(lispobj *start, long n_words)
1753 {
1754     lispobj *end = start + n_words;
1755     lispobj *object_ptr;
1756     int n_words_scavenged;
1757     
1758     for (object_ptr = start;
1759          object_ptr < end;
1760          object_ptr += n_words_scavenged) {
1761
1762         lispobj object = *object_ptr;
1763         
1764         gc_assert(object != 0x01); /* not a forwarding pointer */
1765
1766         if (Pointerp(object)) {
1767             if (from_space_p(object)) {
1768                 /* It currently points to old space. Check for a
1769                  * forwarding pointer. */
1770                 lispobj *ptr = (lispobj *)PTR(object);
1771                 lispobj first_word = *ptr;
1772                 if (first_word == 0x01) {
1773                     /* Yes, there's a forwarding pointer. */
1774                     *object_ptr = ptr[1];
1775                     n_words_scavenged = 1;
1776                 } else {
1777                     /* Scavenge that pointer. */
1778                     n_words_scavenged =
1779                         (scavtab[TypeOf(object)])(object_ptr, object);
1780                 }
1781             } else {
1782                 /* It points somewhere other than oldspace. Leave it
1783                  * alone. */
1784                 n_words_scavenged = 1;
1785             }
1786         } else if ((object & 3) == 0) {
1787             /* It's a fixnum: really easy.. */
1788             n_words_scavenged = 1;
1789         } else {
1790             /* It's some sort of header object or another. */
1791             n_words_scavenged =
1792                 (scavtab[TypeOf(object)])(object_ptr, object);
1793         }
1794     }
1795     gc_assert(object_ptr == end);
1796 }
1797 \f
1798 /*
1799  * code and code-related objects
1800  */
1801
1802 #define RAW_ADDR_OFFSET (6*sizeof(lispobj) - type_FunctionPointer)
1803
1804 static lispobj trans_function_header(lispobj object);
1805 static lispobj trans_boxed(lispobj object);
1806
1807 static int
1808 scav_function_pointer(lispobj *where, lispobj object)
1809 {
1810     lispobj *first_pointer;
1811     lispobj copy;
1812
1813     gc_assert(Pointerp(object));
1814
1815     /* Object is a pointer into from space - no a FP. */
1816     first_pointer = (lispobj *) PTR(object);
1817
1818     /* must transport object -- object may point to either a function
1819      * header, a closure function header, or to a closure header. */
1820
1821     switch (TypeOf(*first_pointer)) {
1822     case type_FunctionHeader:
1823     case type_ClosureFunctionHeader:
1824         copy = trans_function_header(object);
1825         break;
1826     default:
1827         copy = trans_boxed(object);
1828         break;
1829     }
1830
1831     if (copy != object) {
1832         /* Set forwarding pointer */
1833         first_pointer[0] = 0x01;
1834         first_pointer[1] = copy;
1835     }
1836
1837     gc_assert(Pointerp(copy));
1838     gc_assert(!from_space_p(copy));
1839
1840     *where = copy;
1841
1842     return 1;
1843 }
1844
1845 /* Scan a x86 compiled code object, looking for possible fixups that
1846  * have been missed after a move.
1847  *
1848  * Two types of fixups are needed:
1849  * 1. Absolute fixups to within the code object.
1850  * 2. Relative fixups to outside the code object.
1851  *
1852  * Currently only absolute fixups to the constant vector, or to the
1853  * code area are checked. */
1854 void
1855 sniff_code_object(struct code *code, unsigned displacement)
1856 {
1857     int nheader_words, ncode_words, nwords;
1858     void *p;
1859     void *constants_start_addr, *constants_end_addr;
1860     void *code_start_addr, *code_end_addr;
1861     int fixup_found = 0;
1862
1863     if (!check_code_fixups)
1864         return;
1865
1866     /* It's ok if it's byte compiled code. The trace table offset will
1867      * be a fixnum if it's x86 compiled code - check. */
1868     if (code->trace_table_offset & 0x3) {
1869         FSHOW((stderr, "/Sniffing byte compiled code object at %x.\n", code));
1870         return;
1871     }
1872
1873     /* Else it's x86 machine code. */
1874
1875     ncode_words = fixnum_value(code->code_size);
1876     nheader_words = HeaderValue(*(lispobj *)code);
1877     nwords = ncode_words + nheader_words;
1878
1879     constants_start_addr = (void *)code + 5*4;
1880     constants_end_addr = (void *)code + nheader_words*4;
1881     code_start_addr = (void *)code + nheader_words*4;
1882     code_end_addr = (void *)code + nwords*4;
1883
1884     /* Work through the unboxed code. */
1885     for (p = code_start_addr; p < code_end_addr; p++) {
1886         void *data = *(void **)p;
1887         unsigned d1 = *((unsigned char *)p - 1);
1888         unsigned d2 = *((unsigned char *)p - 2);
1889         unsigned d3 = *((unsigned char *)p - 3);
1890         unsigned d4 = *((unsigned char *)p - 4);
1891         unsigned d5 = *((unsigned char *)p - 5);
1892         unsigned d6 = *((unsigned char *)p - 6);
1893
1894         /* Check for code references. */
1895         /* Check for a 32 bit word that looks like an absolute
1896            reference to within the code adea of the code object. */
1897         if ((data >= (code_start_addr-displacement))
1898             && (data < (code_end_addr-displacement))) {
1899             /* function header */
1900             if ((d4 == 0x5e)
1901                 && (((unsigned)p - 4 - 4*HeaderValue(*((unsigned *)p-1))) == (unsigned)code)) {
1902                 /* Skip the function header */
1903                 p += 6*4 - 4 - 1;
1904                 continue;
1905             }
1906             /* the case of PUSH imm32 */
1907             if (d1 == 0x68) {
1908                 fixup_found = 1;
1909                 FSHOW((stderr,
1910                        "/code ref @%x: %.2x %.2x %.2x %.2x %.2x %.2x (%.8x)\n",
1911                        p, d6, d5, d4, d3, d2, d1, data));
1912                 FSHOW((stderr, "/PUSH $0x%.8x\n", data));
1913             }
1914             /* the case of MOV [reg-8],imm32 */
1915             if ((d3 == 0xc7)
1916                 && (d2==0x40 || d2==0x41 || d2==0x42 || d2==0x43
1917                     || d2==0x45 || d2==0x46 || d2==0x47)
1918                 && (d1 == 0xf8)) {
1919                 fixup_found = 1;
1920                 FSHOW((stderr,
1921                        "/code ref @%x: %.2x %.2x %.2x %.2x %.2x %.2x (%.8x)\n",
1922                        p, d6, d5, d4, d3, d2, d1, data));
1923                 FSHOW((stderr, "/MOV [reg-8],$0x%.8x\n", data));
1924             }
1925             /* the case of LEA reg,[disp32] */
1926             if ((d2 == 0x8d) && ((d1 & 0xc7) == 5)) {
1927                 fixup_found = 1;
1928                 FSHOW((stderr,
1929                        "/code ref @%x: %.2x %.2x %.2x %.2x %.2x %.2x (%.8x)\n",
1930                        p, d6, d5, d4, d3, d2, d1, data));
1931                 FSHOW((stderr,"/LEA reg,[$0x%.8x]\n", data));
1932             }
1933         }
1934
1935         /* Check for constant references. */
1936         /* Check for a 32 bit word that looks like an absolute
1937            reference to within the constant vector. Constant references
1938            will be aligned. */
1939         if ((data >= (constants_start_addr-displacement))
1940             && (data < (constants_end_addr-displacement))
1941             && (((unsigned)data & 0x3) == 0)) {
1942             /*  Mov eax,m32 */
1943             if (d1 == 0xa1) {
1944                 fixup_found = 1;
1945                 FSHOW((stderr,
1946                        "/abs const ref @%x: %.2x %.2x %.2x %.2x %.2x %.2x (%.8x)\n",
1947                        p, d6, d5, d4, d3, d2, d1, data));
1948                 FSHOW((stderr,"/MOV eax,0x%.8x\n", data));
1949             }
1950
1951             /*  the case of MOV m32,EAX */
1952             if (d1 == 0xa3) {
1953                 fixup_found = 1;
1954                 FSHOW((stderr,
1955                        "/abs const ref @%x: %.2x %.2x %.2x %.2x %.2x %.2x (%.8x)\n",
1956                        p, d6, d5, d4, d3, d2, d1, data));
1957                 FSHOW((stderr, "/MOV 0x%.8x,eax\n", data));
1958             }
1959
1960             /* the case of CMP m32,imm32 */             
1961             if ((d1 == 0x3d) && (d2 == 0x81)) {
1962                 fixup_found = 1;
1963                 FSHOW((stderr,
1964                        "/abs const ref @%x: %.2x %.2x %.2x %.2x %.2x %.2x (%.8x)\n",
1965                        p, d6, d5, d4, d3, d2, d1, data));
1966                 /* XX Check this */
1967                 FSHOW((stderr, "/CMP 0x%.8x,immed32\n", data));
1968             }
1969
1970             /* Check for a mod=00, r/m=101 byte. */
1971             if ((d1 & 0xc7) == 5) {
1972                 /* Cmp m32,reg */
1973                 if (d2 == 0x39) {
1974                     fixup_found = 1;
1975                     FSHOW((stderr,
1976                            "/abs const ref @%x: %.2x %.2x %.2x %.2x %.2x %.2x (%.8x)\n",
1977                            p, d6, d5, d4, d3, d2, d1, data));
1978                     FSHOW((stderr,"/CMP 0x%.8x,reg\n", data));
1979                 }
1980                 /* the case of CMP reg32,m32 */
1981                 if (d2 == 0x3b) {
1982                     fixup_found = 1;
1983                     FSHOW((stderr,
1984                            "/abs const ref @%x: %.2x %.2x %.2x %.2x %.2x %.2x (%.8x)\n",
1985                            p, d6, d5, d4, d3, d2, d1, data));
1986                     FSHOW((stderr, "/CMP reg32,0x%.8x\n", data));
1987                 }
1988                 /* the case of MOV m32,reg32 */
1989                 if (d2 == 0x89) {
1990                     fixup_found = 1;
1991                     FSHOW((stderr,
1992                            "/abs const ref @%x: %.2x %.2x %.2x %.2x %.2x %.2x (%.8x)\n",
1993                            p, d6, d5, d4, d3, d2, d1, data));
1994                     FSHOW((stderr, "/MOV 0x%.8x,reg32\n", data));
1995                 }
1996                 /* the case of MOV reg32,m32 */
1997                 if (d2 == 0x8b) {
1998                     fixup_found = 1;
1999                     FSHOW((stderr,
2000                            "/abs const ref @%x: %.2x %.2x %.2x %.2x %.2x %.2x (%.8x)\n",
2001                            p, d6, d5, d4, d3, d2, d1, data));
2002                     FSHOW((stderr, "/MOV reg32,0x%.8x\n", data));
2003                 }
2004                 /* the case of LEA reg32,m32 */
2005                 if (d2 == 0x8d) {
2006                     fixup_found = 1;
2007                     FSHOW((stderr,
2008                            "abs const ref @%x: %.2x %.2x %.2x %.2x %.2x %.2x (%.8x)\n",
2009                            p, d6, d5, d4, d3, d2, d1, data));
2010                     FSHOW((stderr, "/LEA reg32,0x%.8x\n", data));
2011                 }
2012             }
2013         }
2014     }
2015
2016     /* If anything was found, print some information on the code
2017      * object. */
2018     if (fixup_found) {
2019         FSHOW((stderr,
2020                "/compiled code object at %x: header words = %d, code words = %d\n",
2021                code, nheader_words, ncode_words));
2022         FSHOW((stderr,
2023                "/const start = %x, end = %x\n",
2024                constants_start_addr, constants_end_addr));
2025         FSHOW((stderr,
2026                "/code start = %x, end = %x\n",
2027                code_start_addr, code_end_addr));
2028     }
2029 }
2030
2031 static void
2032 apply_code_fixups(struct code *old_code, struct code *new_code)
2033 {
2034     int nheader_words, ncode_words, nwords;
2035     void *constants_start_addr, *constants_end_addr;
2036     void *code_start_addr, *code_end_addr;
2037     lispobj fixups = NIL;
2038     unsigned displacement = (unsigned)new_code - (unsigned)old_code;
2039     struct vector *fixups_vector;
2040
2041     /* It's OK if it's byte compiled code. The trace table offset will
2042      * be a fixnum if it's x86 compiled code - check. */
2043     if (new_code->trace_table_offset & 0x3) {
2044 /*      FSHOW((stderr, "/byte compiled code object at %x\n", new_code)); */
2045         return;
2046     }
2047
2048     /* Else it's x86 machine code. */
2049     ncode_words = fixnum_value(new_code->code_size);
2050     nheader_words = HeaderValue(*(lispobj *)new_code);
2051     nwords = ncode_words + nheader_words;
2052     /* FSHOW((stderr,
2053              "/compiled code object at %x: header words = %d, code words = %d\n",
2054              new_code, nheader_words, ncode_words)); */
2055     constants_start_addr = (void *)new_code + 5*4;
2056     constants_end_addr = (void *)new_code + nheader_words*4;
2057     code_start_addr = (void *)new_code + nheader_words*4;
2058     code_end_addr = (void *)new_code + nwords*4;
2059     /*
2060     FSHOW((stderr,
2061            "/const start = %x, end = %x\n",
2062            constants_start_addr,constants_end_addr));
2063     FSHOW((stderr,
2064            "/code start = %x; end = %x\n",
2065            code_start_addr,code_end_addr));
2066     */
2067
2068     /* The first constant should be a pointer to the fixups for this
2069        code objects. Check. */
2070     fixups = new_code->constants[0];
2071
2072     /* It will be 0 or the unbound-marker if there are no fixups, and
2073      * will be an other pointer if it is valid. */
2074     if ((fixups == 0) || (fixups == type_UnboundMarker) || !Pointerp(fixups)) {
2075         /* Check for possible errors. */
2076         if (check_code_fixups)
2077             sniff_code_object(new_code, displacement);
2078
2079         /*fprintf(stderr,"Fixups for code object not found!?\n");
2080           fprintf(stderr,"*** Compiled code object at %x: header_words=%d code_words=%d .\n",
2081           new_code, nheader_words, ncode_words);
2082           fprintf(stderr,"*** Const. start = %x; end= %x; Code start = %x; end = %x\n",
2083           constants_start_addr,constants_end_addr,
2084           code_start_addr,code_end_addr);*/
2085         return;
2086     }
2087
2088     fixups_vector = (struct vector *)PTR(fixups);
2089
2090     /* Could be pointing to a forwarding pointer. */
2091     if (Pointerp(fixups) && (find_page_index((void*)fixups_vector) != -1)
2092         && (fixups_vector->header == 0x01)) {
2093         /* If so, then follow it. */
2094         /*SHOW("following pointer to a forwarding pointer");*/
2095         fixups_vector = (struct vector *)PTR((lispobj)fixups_vector->length);
2096     }
2097
2098     /*SHOW("got fixups");*/
2099
2100     if (TypeOf(fixups_vector->header) == type_SimpleArrayUnsignedByte32) {
2101         /* Got the fixups for the code block. Now work through the vector,
2102            and apply a fixup at each address. */
2103         int length = fixnum_value(fixups_vector->length);
2104         int i;
2105         for (i = 0; i < length; i++) {
2106             unsigned offset = fixups_vector->data[i];
2107             /* Now check the current value of offset. */
2108             unsigned old_value =
2109                 *(unsigned *)((unsigned)code_start_addr + offset);
2110
2111             /* If it's within the old_code object then it must be an
2112              * absolute fixup (relative ones are not saved) */
2113             if ((old_value >= (unsigned)old_code)
2114                 && (old_value < ((unsigned)old_code + nwords*4)))
2115                 /* So add the dispacement. */
2116                 *(unsigned *)((unsigned)code_start_addr + offset) =
2117                     old_value + displacement;
2118             else
2119                 /* It is outside the old code object so it must be a
2120                  * relative fixup (absolute fixups are not saved). So
2121                  * subtract the displacement. */
2122                 *(unsigned *)((unsigned)code_start_addr + offset) =
2123                     old_value - displacement;
2124         }
2125     }
2126
2127     /* Check for possible errors. */
2128     if (check_code_fixups) {
2129         sniff_code_object(new_code,displacement);
2130     }
2131 }
2132
2133 static struct code *
2134 trans_code(struct code *code)
2135 {
2136     struct code *new_code;
2137     lispobj l_code, l_new_code;
2138     int nheader_words, ncode_words, nwords;
2139     unsigned long displacement;
2140     lispobj fheaderl, *prev_pointer;
2141
2142     /* FSHOW((stderr,
2143              "\n/transporting code object located at 0x%08x\n",
2144              (unsigned long) code)); */
2145
2146     /* If object has already been transported, just return pointer. */
2147     if (*((lispobj *)code) == 0x01)
2148         return (struct code*)(((lispobj *)code)[1]);
2149
2150     gc_assert(TypeOf(code->header) == type_CodeHeader);
2151
2152     /* Prepare to transport the code vector. */
2153     l_code = (lispobj) code | type_OtherPointer;
2154
2155     ncode_words = fixnum_value(code->code_size);
2156     nheader_words = HeaderValue(code->header);
2157     nwords = ncode_words + nheader_words;
2158     nwords = CEILING(nwords, 2);
2159
2160     l_new_code = copy_large_object(l_code, nwords);
2161     new_code = (struct code *) PTR(l_new_code);
2162
2163     /* may not have been moved.. */
2164     if (new_code == code)
2165         return new_code;
2166
2167     displacement = l_new_code - l_code;
2168
2169     /*
2170     FSHOW((stderr,
2171            "/old code object at 0x%08x, new code object at 0x%08x\n",
2172            (unsigned long) code,
2173            (unsigned long) new_code));
2174     FSHOW((stderr, "/Code object is %d words long.\n", nwords));
2175     */
2176
2177     /* Set forwarding pointer. */
2178     ((lispobj *)code)[0] = 0x01;
2179     ((lispobj *)code)[1] = l_new_code;
2180
2181     /* Set forwarding pointers for all the function headers in the
2182      * code object. Also fix all self pointers. */
2183
2184     fheaderl = code->entry_points;
2185     prev_pointer = &new_code->entry_points;
2186
2187     while (fheaderl != NIL) {
2188         struct function *fheaderp, *nfheaderp;
2189         lispobj nfheaderl;
2190
2191         fheaderp = (struct function *) PTR(fheaderl);
2192         gc_assert(TypeOf(fheaderp->header) == type_FunctionHeader);
2193
2194         /* Calculate the new function pointer and the new */
2195         /* function header. */
2196         nfheaderl = fheaderl + displacement;
2197         nfheaderp = (struct function *) PTR(nfheaderl);
2198
2199         /* Set forwarding pointer. */
2200         ((lispobj *)fheaderp)[0] = 0x01;
2201         ((lispobj *)fheaderp)[1] = nfheaderl;
2202
2203         /* Fix self pointer. */
2204         nfheaderp->self = nfheaderl + RAW_ADDR_OFFSET;
2205
2206         *prev_pointer = nfheaderl;
2207
2208         fheaderl = fheaderp->next;
2209         prev_pointer = &nfheaderp->next;
2210     }
2211
2212     /*  sniff_code_object(new_code,displacement);*/
2213     apply_code_fixups(code,new_code);
2214
2215     return new_code;
2216 }
2217
2218 static int
2219 scav_code_header(lispobj *where, lispobj object)
2220 {
2221     struct code *code;
2222     int n_header_words, n_code_words, n_words;
2223     lispobj entry_point;        /* tagged pointer to entry point */
2224     struct function *function_ptr; /* untagged pointer to entry point */
2225
2226     code = (struct code *) where;
2227     n_code_words = fixnum_value(code->code_size);
2228     n_header_words = HeaderValue(object);
2229     n_words = n_code_words + n_header_words;
2230     n_words = CEILING(n_words, 2);
2231
2232     /* Scavenge the boxed section of the code data block. */
2233     scavenge(where + 1, n_header_words - 1);
2234
2235     /* Scavenge the boxed section of each function object in the */
2236     /* code data block. */
2237     for (entry_point = code->entry_points;
2238          entry_point != NIL;
2239          entry_point = function_ptr->next) {
2240
2241         gc_assert(Pointerp(entry_point));
2242
2243         function_ptr = (struct function *) PTR(entry_point);
2244         gc_assert(TypeOf(function_ptr->header) == type_FunctionHeader);
2245
2246         scavenge(&function_ptr->name, 1);
2247         scavenge(&function_ptr->arglist, 1);
2248         scavenge(&function_ptr->type, 1);
2249     }
2250         
2251     return n_words;
2252 }
2253
2254 static lispobj
2255 trans_code_header(lispobj object)
2256 {
2257     struct code *ncode;
2258
2259     ncode = trans_code((struct code *) PTR(object));
2260     return (lispobj) ncode | type_OtherPointer;
2261 }
2262
2263 static int
2264 size_code_header(lispobj *where)
2265 {
2266     struct code *code;
2267     int nheader_words, ncode_words, nwords;
2268
2269     code = (struct code *) where;
2270         
2271     ncode_words = fixnum_value(code->code_size);
2272     nheader_words = HeaderValue(code->header);
2273     nwords = ncode_words + nheader_words;
2274     nwords = CEILING(nwords, 2);
2275
2276     return nwords;
2277 }
2278
2279 static int
2280 scav_return_pc_header(lispobj *where, lispobj object)
2281 {
2282     lose("attempted to scavenge a return PC header where=0x%08x object=0x%08x",
2283          (unsigned long) where,
2284          (unsigned long) object);
2285     return 0; /* bogus return value to satisfy static type checking */
2286 }
2287
2288 static lispobj
2289 trans_return_pc_header(lispobj object)
2290 {
2291     struct function *return_pc;
2292     unsigned long offset;
2293     struct code *code, *ncode;
2294
2295     SHOW("/trans_return_pc_header: Will this work?");
2296
2297     return_pc = (struct function *) PTR(object);
2298     offset = HeaderValue(return_pc->header) * 4;
2299
2300     /* Transport the whole code object. */
2301     code = (struct code *) ((unsigned long) return_pc - offset);
2302     ncode = trans_code(code);
2303
2304     return ((lispobj) ncode + offset) | type_OtherPointer;
2305 }
2306
2307 /* On the 386, closures hold a pointer to the raw address instead of the
2308  * function object. */
2309 #ifdef __i386__
2310 static int
2311 scav_closure_header(lispobj *where, lispobj object)
2312 {
2313     struct closure *closure;
2314     lispobj fun;
2315
2316     closure = (struct closure *)where;
2317     fun = closure->function - RAW_ADDR_OFFSET;
2318     scavenge(&fun, 1);
2319     /* The function may have moved so update the raw address. But
2320      * don't write unnecessarily. */
2321     if (closure->function != fun + RAW_ADDR_OFFSET)
2322         closure->function = fun + RAW_ADDR_OFFSET;
2323
2324     return 2;
2325 }
2326 #endif
2327
2328 static int
2329 scav_function_header(lispobj *where, lispobj object)
2330 {
2331     lose("attempted to scavenge a function header where=0x%08x object=0x%08x",
2332          (unsigned long) where,
2333          (unsigned long) object);
2334     return 0; /* bogus return value to satisfy static type checking */
2335 }
2336
2337 static lispobj
2338 trans_function_header(lispobj object)
2339 {
2340     struct function *fheader;
2341     unsigned long offset;
2342     struct code *code, *ncode;
2343
2344     fheader = (struct function *) PTR(object);
2345     offset = HeaderValue(fheader->header) * 4;
2346
2347     /* Transport the whole code object. */
2348     code = (struct code *) ((unsigned long) fheader - offset);
2349     ncode = trans_code(code);
2350
2351     return ((lispobj) ncode + offset) | type_FunctionPointer;
2352 }
2353 \f
2354 /*
2355  * instances
2356  */
2357
2358 static int
2359 scav_instance_pointer(lispobj *where, lispobj object)
2360 {
2361     lispobj copy, *first_pointer;
2362
2363     /* Object is a pointer into from space - not a FP. */
2364     copy = trans_boxed(object);
2365
2366     gc_assert(copy != object);
2367
2368     first_pointer = (lispobj *) PTR(object);
2369
2370     /* Set forwarding pointer. */
2371     first_pointer[0] = 0x01;
2372     first_pointer[1] = copy;
2373     *where = copy;
2374
2375     return 1;
2376 }
2377 \f
2378 /*
2379  * lists and conses
2380  */
2381
2382 static lispobj trans_list(lispobj object);
2383
2384 static int
2385 scav_list_pointer(lispobj *where, lispobj object)
2386 {
2387     lispobj first, *first_pointer;
2388
2389     gc_assert(Pointerp(object));
2390
2391     /* Object is a pointer into from space - not FP. */
2392
2393     first = trans_list(object);
2394     gc_assert(first != object);
2395
2396     first_pointer = (lispobj *) PTR(object);
2397
2398     /* Set forwarding pointer */
2399     first_pointer[0] = 0x01;
2400     first_pointer[1] = first;
2401
2402     gc_assert(Pointerp(first));
2403     gc_assert(!from_space_p(first));
2404     *where = first;
2405     return 1;
2406 }
2407
2408 static lispobj
2409 trans_list(lispobj object)
2410 {
2411     lispobj new_list_pointer;
2412     struct cons *cons, *new_cons;
2413     lispobj cdr;
2414
2415     gc_assert(from_space_p(object));
2416
2417     cons = (struct cons *) PTR(object);
2418
2419     /* Copy 'object'. */
2420     new_cons = (struct cons *) gc_quick_alloc(sizeof(struct cons));
2421     new_cons->car = cons->car;
2422     new_cons->cdr = cons->cdr; /* updated later */
2423     new_list_pointer = (lispobj)new_cons | LowtagOf(object);
2424
2425     /* Grab the cdr before it is clobbered. */
2426     cdr = cons->cdr;
2427
2428     /* Set forwarding pointer (clobbers start of list). */
2429     cons->car = 0x01;
2430     cons->cdr = new_list_pointer;
2431
2432     /* Try to linearize the list in the cdr direction to help reduce
2433      * paging. */
2434     while (1) {
2435         lispobj  new_cdr;
2436         struct cons *cdr_cons, *new_cdr_cons;
2437
2438         if (LowtagOf(cdr) != type_ListPointer || !from_space_p(cdr)
2439             || (*((lispobj *)PTR(cdr)) == 0x01))
2440             break;
2441
2442         cdr_cons = (struct cons *) PTR(cdr);
2443
2444         /* Copy 'cdr'. */
2445         new_cdr_cons = (struct cons*) gc_quick_alloc(sizeof(struct cons));
2446         new_cdr_cons->car = cdr_cons->car;
2447         new_cdr_cons->cdr = cdr_cons->cdr;
2448         new_cdr = (lispobj)new_cdr_cons | LowtagOf(cdr);
2449
2450         /* Grab the cdr before it is clobbered. */
2451         cdr = cdr_cons->cdr;
2452
2453         /* Set forwarding pointer. */
2454         cdr_cons->car = 0x01;
2455         cdr_cons->cdr = new_cdr;
2456
2457         /* Update the cdr of the last cons copied into new space to
2458          * keep the newspace scavenge from having to do it. */
2459         new_cons->cdr = new_cdr;
2460
2461         new_cons = new_cdr_cons;
2462     }
2463
2464     return new_list_pointer;
2465 }
2466
2467 \f
2468 /*
2469  * scavenging and transporting other pointers
2470  */
2471
2472 static int
2473 scav_other_pointer(lispobj *where, lispobj object)
2474 {
2475     lispobj first, *first_pointer;
2476
2477     gc_assert(Pointerp(object));
2478
2479     /* Object is a pointer into from space - not FP. */
2480     first_pointer = (lispobj *) PTR(object);
2481
2482     first = (transother[TypeOf(*first_pointer)])(object);
2483
2484     if (first != object) {
2485         /* Set forwarding pointer. */
2486         first_pointer[0] = 0x01;
2487         first_pointer[1] = first;
2488         *where = first;
2489     }
2490
2491     gc_assert(Pointerp(first));
2492     gc_assert(!from_space_p(first));
2493
2494     return 1;
2495 }
2496 \f
2497 /*
2498  * immediate, boxed, and unboxed objects
2499  */
2500
2501 static int
2502 size_pointer(lispobj *where)
2503 {
2504     return 1;
2505 }
2506
2507 static int
2508 scav_immediate(lispobj *where, lispobj object)
2509 {
2510     return 1;
2511 }
2512
2513 static lispobj
2514 trans_immediate(lispobj object)
2515 {
2516     lose("trying to transport an immediate");
2517     return NIL; /* bogus return value to satisfy static type checking */
2518 }
2519
2520 static int
2521 size_immediate(lispobj *where)
2522 {
2523     return 1;
2524 }
2525
2526
2527 static int
2528 scav_boxed(lispobj *where, lispobj object)
2529 {
2530     return 1;
2531 }
2532
2533 static lispobj
2534 trans_boxed(lispobj object)
2535 {
2536     lispobj header;
2537     unsigned long length;
2538
2539     gc_assert(Pointerp(object));
2540
2541     header = *((lispobj *) PTR(object));
2542     length = HeaderValue(header) + 1;
2543     length = CEILING(length, 2);
2544
2545     return copy_object(object, length);
2546 }
2547
2548 static lispobj
2549 trans_boxed_large(lispobj object)
2550 {
2551     lispobj header;
2552     unsigned long length;
2553
2554     gc_assert(Pointerp(object));
2555
2556     header = *((lispobj *) PTR(object));
2557     length = HeaderValue(header) + 1;
2558     length = CEILING(length, 2);
2559
2560     return copy_large_object(object, length);
2561 }
2562
2563 static int
2564 size_boxed(lispobj *where)
2565 {
2566     lispobj header;
2567     unsigned long length;
2568
2569     header = *where;
2570     length = HeaderValue(header) + 1;
2571     length = CEILING(length, 2);
2572
2573     return length;
2574 }
2575
2576 static int
2577 scav_fdefn(lispobj *where, lispobj object)
2578 {
2579     struct fdefn *fdefn;
2580
2581     fdefn = (struct fdefn *)where;
2582
2583     /* FSHOW((stderr, "scav_fdefn, function = %p, raw_addr = %p\n", 
2584        fdefn->function, fdefn->raw_addr)); */
2585
2586     if ((char *)(fdefn->function + RAW_ADDR_OFFSET) == fdefn->raw_addr) {
2587         scavenge(where + 1, sizeof(struct fdefn)/sizeof(lispobj) - 1);
2588
2589         /* Don't write unnecessarily. */
2590         if (fdefn->raw_addr != (char *)(fdefn->function + RAW_ADDR_OFFSET))
2591             fdefn->raw_addr = (char *)(fdefn->function + RAW_ADDR_OFFSET);
2592
2593         return sizeof(struct fdefn) / sizeof(lispobj);
2594     } else {
2595         return 1;
2596     }
2597 }
2598
2599 static int
2600 scav_unboxed(lispobj *where, lispobj object)
2601 {
2602     unsigned long length;
2603
2604     length = HeaderValue(object) + 1;
2605     length = CEILING(length, 2);
2606
2607     return length;
2608 }
2609
2610 static lispobj
2611 trans_unboxed(lispobj object)
2612 {
2613     lispobj header;
2614     unsigned long length;
2615
2616
2617     gc_assert(Pointerp(object));
2618
2619     header = *((lispobj *) PTR(object));
2620     length = HeaderValue(header) + 1;
2621     length = CEILING(length, 2);
2622
2623     return copy_unboxed_object(object, length);
2624 }
2625
2626 static lispobj
2627 trans_unboxed_large(lispobj object)
2628 {
2629     lispobj header;
2630     unsigned long length;
2631
2632
2633     gc_assert(Pointerp(object));
2634
2635     header = *((lispobj *) PTR(object));
2636     length = HeaderValue(header) + 1;
2637     length = CEILING(length, 2);
2638
2639     return copy_large_unboxed_object(object, length);
2640 }
2641
2642 static int
2643 size_unboxed(lispobj *where)
2644 {
2645     lispobj header;
2646     unsigned long length;
2647
2648     header = *where;
2649     length = HeaderValue(header) + 1;
2650     length = CEILING(length, 2);
2651
2652     return length;
2653 }
2654 \f
2655 /*
2656  * vector-like objects
2657  */
2658
2659 #define NWORDS(x,y) (CEILING((x),(y)) / (y))
2660
2661 static int
2662 scav_string(lispobj *where, lispobj object)
2663 {
2664     struct vector *vector;
2665     int length, nwords;
2666
2667     /* NOTE: Strings contain one more byte of data than the length */
2668     /* slot indicates. */
2669
2670     vector = (struct vector *) where;
2671     length = fixnum_value(vector->length) + 1;
2672     nwords = CEILING(NWORDS(length, 4) + 2, 2);
2673
2674     return nwords;
2675 }
2676
2677 static lispobj
2678 trans_string(lispobj object)
2679 {
2680     struct vector *vector;
2681     int length, nwords;
2682
2683     gc_assert(Pointerp(object));
2684
2685     /* NOTE: A string contains one more byte of data (a terminating
2686      * '\0' to help when interfacing with C functions) than indicated
2687      * by the length slot. */
2688
2689     vector = (struct vector *) PTR(object);
2690     length = fixnum_value(vector->length) + 1;
2691     nwords = CEILING(NWORDS(length, 4) + 2, 2);
2692
2693     return copy_large_unboxed_object(object, nwords);
2694 }
2695
2696 static int
2697 size_string(lispobj *where)
2698 {
2699     struct vector *vector;
2700     int length, nwords;
2701
2702     /* NOTE: A string contains one more byte of data (a terminating
2703      * '\0' to help when interfacing with C functions) than indicated
2704      * by the length slot. */
2705
2706     vector = (struct vector *) where;
2707     length = fixnum_value(vector->length) + 1;
2708     nwords = CEILING(NWORDS(length, 4) + 2, 2);
2709
2710     return nwords;
2711 }
2712
2713 /* FIXME: What does this mean? */
2714 int gencgc_hash = 1;
2715
2716 static int
2717 scav_vector(lispobj *where, lispobj object)
2718 {
2719     unsigned int kv_length;
2720     lispobj *kv_vector;
2721     unsigned int length = 0; /* (0 = dummy to stop GCC warning) */
2722     lispobj *hash_table;
2723     lispobj empty_symbol;
2724     unsigned int *index_vector = NULL; /* (NULL = dummy to stop GCC warning) */
2725     unsigned int *next_vector = NULL; /* (NULL = dummy to stop GCC warning) */
2726     unsigned int *hash_vector = NULL; /* (NULL = dummy to stop GCC warning) */
2727     lispobj weak_p_obj;
2728     unsigned next_vector_length = 0;
2729
2730     /* FIXME: A comment explaining this would be nice. It looks as
2731      * though SB-VM:VECTOR-VALID-HASHING-SUBTYPE is set for EQ-based
2732      * hash tables in the Lisp HASH-TABLE code, and nowhere else. */
2733     if (HeaderValue(object) != subtype_VectorValidHashing)
2734         return 1;
2735
2736     if (!gencgc_hash) {
2737         /* This is set for backward compatibility. FIXME: Do we need
2738          * this any more? */
2739         *where = (subtype_VectorMustRehash << type_Bits) | type_SimpleVector;
2740         return 1;
2741     }
2742
2743     kv_length = fixnum_value(where[1]);
2744     kv_vector = where + 2;  /* Skip the header and length. */
2745     /*FSHOW((stderr,"/kv_length = %d\n", kv_length));*/
2746
2747     /* Scavenge element 0, which may be a hash-table structure. */
2748     scavenge(where+2, 1);
2749     if (!Pointerp(where[2])) {
2750         lose("no pointer at %x in hash table", where[2]);
2751     }
2752     hash_table = (lispobj *)PTR(where[2]);
2753     /*FSHOW((stderr,"/hash_table = %x\n", hash_table));*/
2754     if (TypeOf(hash_table[0]) != type_InstanceHeader) {
2755         lose("hash table not instance (%x at %x)", hash_table[0], hash_table);
2756     }
2757
2758     /* Scavenge element 1, which should be some internal symbol that
2759      * the hash table code reserves for marking empty slots. */
2760     scavenge(where+3, 1);
2761     if (!Pointerp(where[3])) {
2762         lose("not empty-hash-table-slot symbol pointer: %x", where[3]);
2763     }
2764     empty_symbol = where[3];
2765     /* fprintf(stderr,"* empty_symbol = %x\n", empty_symbol);*/
2766     if (TypeOf(*(lispobj *)PTR(empty_symbol)) != type_SymbolHeader) {
2767         lose("not a symbol where empty-hash-table-slot symbol expected: %x",
2768              *(lispobj *)PTR(empty_symbol));
2769     }
2770
2771     /* Scavenge hash table, which will fix the positions of the other
2772      * needed objects. */
2773     scavenge(hash_table, 16);
2774
2775     /* Cross-check the kv_vector. */
2776     if (where != (lispobj *)PTR(hash_table[9])) {
2777         lose("hash_table table!=this table %x", hash_table[9]);
2778     }
2779
2780     /* WEAK-P */
2781     weak_p_obj = hash_table[10];
2782
2783     /* index vector */
2784     {
2785         lispobj index_vector_obj = hash_table[13];
2786
2787         if (Pointerp(index_vector_obj) &&
2788             (TypeOf(*(lispobj *)PTR(index_vector_obj)) == type_SimpleArrayUnsignedByte32)) {
2789             index_vector = ((unsigned int *)PTR(index_vector_obj)) + 2;
2790             /*FSHOW((stderr, "/index_vector = %x\n",index_vector));*/
2791             length = fixnum_value(((unsigned int *)PTR(index_vector_obj))[1]);
2792             /*FSHOW((stderr, "/length = %d\n", length));*/
2793         } else {
2794             lose("invalid index_vector %x", index_vector_obj);
2795         }
2796     }
2797
2798     /* next vector */
2799     {
2800         lispobj next_vector_obj = hash_table[14];
2801
2802         if (Pointerp(next_vector_obj) &&
2803             (TypeOf(*(lispobj *)PTR(next_vector_obj)) == type_SimpleArrayUnsignedByte32)) {
2804             next_vector = ((unsigned int *)PTR(next_vector_obj)) + 2;
2805             /*FSHOW((stderr, "/next_vector = %x\n", next_vector));*/
2806             next_vector_length = fixnum_value(((unsigned int *)PTR(next_vector_obj))[1]);
2807             /*FSHOW((stderr, "/next_vector_length = %d\n", next_vector_length));*/
2808         } else {
2809             lose("invalid next_vector %x", next_vector_obj);
2810         }
2811     }
2812
2813     /* maybe hash vector */
2814     {
2815         /* FIXME: This bare "15" offset should become a symbolic
2816          * expression of some sort. And all the other bare offsets
2817          * too. And the bare "16" in scavenge(hash_table, 16). And
2818          * probably other stuff too. Ugh.. */
2819         lispobj hash_vector_obj = hash_table[15];
2820
2821         if (Pointerp(hash_vector_obj) &&
2822             (TypeOf(*(lispobj *)PTR(hash_vector_obj))
2823              == type_SimpleArrayUnsignedByte32)) {
2824             hash_vector = ((unsigned int *)PTR(hash_vector_obj)) + 2;
2825             /*FSHOW((stderr, "/hash_vector = %x\n", hash_vector));*/
2826             gc_assert(fixnum_value(((unsigned int *)PTR(hash_vector_obj))[1])
2827                       == next_vector_length);
2828         } else {
2829             hash_vector = NULL;
2830             /*FSHOW((stderr, "/no hash_vector: %x\n", hash_vector_obj));*/
2831         }
2832     }
2833
2834     /* These lengths could be different as the index_vector can be a
2835      * different length from the others, a larger index_vector could help
2836      * reduce collisions. */
2837     gc_assert(next_vector_length*2 == kv_length);
2838
2839     /* now all set up.. */
2840
2841     /* Work through the KV vector. */
2842     {
2843         int i;
2844         for (i = 1; i < next_vector_length; i++) {
2845             lispobj old_key = kv_vector[2*i];
2846             unsigned int  old_index = (old_key & 0x1fffffff)%length;
2847
2848             /* Scavenge the key and value. */
2849             scavenge(&kv_vector[2*i],2);
2850
2851             /* Check whether the key has moved and is EQ based. */
2852             {
2853                 lispobj new_key = kv_vector[2*i];
2854                 unsigned int new_index = (new_key & 0x1fffffff)%length;
2855
2856                 if ((old_index != new_index) &&
2857                     ((!hash_vector) || (hash_vector[i] == 0x80000000)) &&
2858                     ((new_key != empty_symbol) ||
2859                      (kv_vector[2*i] != empty_symbol))) {
2860
2861                     /*FSHOW((stderr,
2862                            "* EQ key %d moved from %x to %x; index %d to %d\n",
2863                            i, old_key, new_key, old_index, new_index));*/
2864
2865                     if (index_vector[old_index] != 0) {
2866                         /*FSHOW((stderr, "/P1 %d\n", index_vector[old_index]));*/
2867
2868                         /* Unlink the key from the old_index chain. */
2869                         if (index_vector[old_index] == i) {
2870                             /*FSHOW((stderr, "/P2a %d\n", next_vector[i]));*/
2871                             index_vector[old_index] = next_vector[i];
2872                             /* Link it into the needing rehash chain. */
2873                             next_vector[i] = fixnum_value(hash_table[11]);
2874                             hash_table[11] = make_fixnum(i);
2875                             /*SHOW("P2");*/
2876                         } else {
2877                             unsigned prior = index_vector[old_index];
2878                             unsigned next = next_vector[prior];
2879
2880                             /*FSHOW((stderr, "/P3a %d %d\n", prior, next));*/
2881
2882                             while (next != 0) {
2883                                 /*FSHOW((stderr, "/P3b %d %d\n", prior, next));*/
2884                                 if (next == i) {
2885                                     /* Unlink it. */
2886                                     next_vector[prior] = next_vector[next];
2887                                     /* Link it into the needing rehash
2888                                      * chain. */
2889                                     next_vector[next] =
2890                                         fixnum_value(hash_table[11]);
2891                                     hash_table[11] = make_fixnum(next);
2892                                     /*SHOW("/P3");*/
2893                                     break;
2894                                 }
2895                                 prior = next;
2896                                 next = next_vector[next];
2897                             }
2898                         }
2899                     }
2900                 }
2901             }
2902         }
2903     }
2904     return (CEILING(kv_length + 2, 2));
2905 }
2906
2907 static lispobj
2908 trans_vector(lispobj object)
2909 {
2910     struct vector *vector;
2911     int length, nwords;
2912
2913     gc_assert(Pointerp(object));
2914
2915     vector = (struct vector *) PTR(object);
2916
2917     length = fixnum_value(vector->length);
2918     nwords = CEILING(length + 2, 2);
2919
2920     return copy_large_object(object, nwords);
2921 }
2922
2923 static int
2924 size_vector(lispobj *where)
2925 {
2926     struct vector *vector;
2927     int length, nwords;
2928
2929     vector = (struct vector *) where;
2930     length = fixnum_value(vector->length);
2931     nwords = CEILING(length + 2, 2);
2932
2933     return nwords;
2934 }
2935
2936
2937 static int
2938 scav_vector_bit(lispobj *where, lispobj object)
2939 {
2940     struct vector *vector;
2941     int length, nwords;
2942
2943     vector = (struct vector *) where;
2944     length = fixnum_value(vector->length);
2945     nwords = CEILING(NWORDS(length, 32) + 2, 2);
2946
2947     return nwords;
2948 }
2949
2950 static lispobj
2951 trans_vector_bit(lispobj object)
2952 {
2953     struct vector *vector;
2954     int length, nwords;
2955
2956     gc_assert(Pointerp(object));
2957
2958     vector = (struct vector *) PTR(object);
2959     length = fixnum_value(vector->length);
2960     nwords = CEILING(NWORDS(length, 32) + 2, 2);
2961
2962     return copy_large_unboxed_object(object, nwords);
2963 }
2964
2965 static int
2966 size_vector_bit(lispobj *where)
2967 {
2968     struct vector *vector;
2969     int length, nwords;
2970
2971     vector = (struct vector *) where;
2972     length = fixnum_value(vector->length);
2973     nwords = CEILING(NWORDS(length, 32) + 2, 2);
2974
2975     return nwords;
2976 }
2977
2978
2979 static int
2980 scav_vector_unsigned_byte_2(lispobj *where, lispobj object)
2981 {
2982     struct vector *vector;
2983     int length, nwords;
2984
2985     vector = (struct vector *) where;
2986     length = fixnum_value(vector->length);
2987     nwords = CEILING(NWORDS(length, 16) + 2, 2);
2988
2989     return nwords;
2990 }
2991
2992 static lispobj
2993 trans_vector_unsigned_byte_2(lispobj object)
2994 {
2995     struct vector *vector;
2996     int length, nwords;
2997
2998     gc_assert(Pointerp(object));
2999
3000     vector = (struct vector *) PTR(object);
3001     length = fixnum_value(vector->length);
3002     nwords = CEILING(NWORDS(length, 16) + 2, 2);
3003
3004     return copy_large_unboxed_object(object, nwords);
3005 }
3006
3007 static int
3008 size_vector_unsigned_byte_2(lispobj *where)
3009 {
3010     struct vector *vector;
3011     int length, nwords;
3012
3013     vector = (struct vector *) where;
3014     length = fixnum_value(vector->length);
3015     nwords = CEILING(NWORDS(length, 16) + 2, 2);
3016
3017     return nwords;
3018 }
3019
3020
3021 static int
3022 scav_vector_unsigned_byte_4(lispobj *where, lispobj object)
3023 {
3024     struct vector *vector;
3025     int length, nwords;
3026
3027     vector = (struct vector *) where;
3028     length = fixnum_value(vector->length);
3029     nwords = CEILING(NWORDS(length, 8) + 2, 2);
3030
3031     return nwords;
3032 }
3033
3034 static lispobj
3035 trans_vector_unsigned_byte_4(lispobj object)
3036 {
3037     struct vector *vector;
3038     int length, nwords;
3039
3040     gc_assert(Pointerp(object));
3041
3042     vector = (struct vector *) PTR(object);
3043     length = fixnum_value(vector->length);
3044     nwords = CEILING(NWORDS(length, 8) + 2, 2);
3045
3046     return copy_large_unboxed_object(object, nwords);
3047 }
3048
3049 static int
3050 size_vector_unsigned_byte_4(lispobj *where)
3051 {
3052     struct vector *vector;
3053     int length, nwords;
3054
3055     vector = (struct vector *) where;
3056     length = fixnum_value(vector->length);
3057     nwords = CEILING(NWORDS(length, 8) + 2, 2);
3058
3059     return nwords;
3060 }
3061
3062 static int
3063 scav_vector_unsigned_byte_8(lispobj *where, lispobj object)
3064 {
3065     struct vector *vector;
3066     int length, nwords;
3067
3068     vector = (struct vector *) where;
3069     length = fixnum_value(vector->length);
3070     nwords = CEILING(NWORDS(length, 4) + 2, 2);
3071
3072     return nwords;
3073 }
3074
3075 static lispobj
3076 trans_vector_unsigned_byte_8(lispobj object)
3077 {
3078     struct vector *vector;
3079     int length, nwords;
3080
3081     gc_assert(Pointerp(object));
3082
3083     vector = (struct vector *) PTR(object);
3084     length = fixnum_value(vector->length);
3085     nwords = CEILING(NWORDS(length, 4) + 2, 2);
3086
3087     return copy_large_unboxed_object(object, nwords);
3088 }
3089
3090 static int
3091 size_vector_unsigned_byte_8(lispobj *where)
3092 {
3093     struct vector *vector;
3094     int length, nwords;
3095
3096     vector = (struct vector *) where;
3097     length = fixnum_value(vector->length);
3098     nwords = CEILING(NWORDS(length, 4) + 2, 2);
3099
3100     return nwords;
3101 }
3102
3103
3104 static int
3105 scav_vector_unsigned_byte_16(lispobj *where, lispobj object)
3106 {
3107     struct vector *vector;
3108     int length, nwords;
3109
3110     vector = (struct vector *) where;
3111     length = fixnum_value(vector->length);
3112     nwords = CEILING(NWORDS(length, 2) + 2, 2);
3113
3114     return nwords;
3115 }
3116
3117 static lispobj
3118 trans_vector_unsigned_byte_16(lispobj object)
3119 {
3120     struct vector *vector;
3121     int length, nwords;
3122
3123     gc_assert(Pointerp(object));
3124
3125     vector = (struct vector *) PTR(object);
3126     length = fixnum_value(vector->length);
3127     nwords = CEILING(NWORDS(length, 2) + 2, 2);
3128
3129     return copy_large_unboxed_object(object, nwords);
3130 }
3131
3132 static int
3133 size_vector_unsigned_byte_16(lispobj *where)
3134 {
3135     struct vector *vector;
3136     int length, nwords;
3137
3138     vector = (struct vector *) where;
3139     length = fixnum_value(vector->length);
3140     nwords = CEILING(NWORDS(length, 2) + 2, 2);
3141
3142     return nwords;
3143 }
3144
3145 static int
3146 scav_vector_unsigned_byte_32(lispobj *where, lispobj object)
3147 {
3148     struct vector *vector;
3149     int length, nwords;
3150
3151     vector = (struct vector *) where;
3152     length = fixnum_value(vector->length);
3153     nwords = CEILING(length + 2, 2);
3154
3155     return nwords;
3156 }
3157
3158 static lispobj
3159 trans_vector_unsigned_byte_32(lispobj object)
3160 {
3161     struct vector *vector;
3162     int length, nwords;
3163
3164     gc_assert(Pointerp(object));
3165
3166     vector = (struct vector *) PTR(object);
3167     length = fixnum_value(vector->length);
3168     nwords = CEILING(length + 2, 2);
3169
3170     return copy_large_unboxed_object(object, nwords);
3171 }
3172
3173 static int
3174 size_vector_unsigned_byte_32(lispobj *where)
3175 {
3176     struct vector *vector;
3177     int length, nwords;
3178
3179     vector = (struct vector *) where;
3180     length = fixnum_value(vector->length);
3181     nwords = CEILING(length + 2, 2);
3182
3183     return nwords;
3184 }
3185
3186 static int
3187 scav_vector_single_float(lispobj *where, lispobj object)
3188 {
3189     struct vector *vector;
3190     int length, nwords;
3191
3192     vector = (struct vector *) where;
3193     length = fixnum_value(vector->length);
3194     nwords = CEILING(length + 2, 2);
3195
3196     return nwords;
3197 }
3198
3199 static lispobj
3200 trans_vector_single_float(lispobj object)
3201 {
3202     struct vector *vector;
3203     int length, nwords;
3204
3205     gc_assert(Pointerp(object));
3206
3207     vector = (struct vector *) PTR(object);
3208     length = fixnum_value(vector->length);
3209     nwords = CEILING(length + 2, 2);
3210
3211     return copy_large_unboxed_object(object, nwords);
3212 }
3213
3214 static int
3215 size_vector_single_float(lispobj *where)
3216 {
3217     struct vector *vector;
3218     int length, nwords;
3219
3220     vector = (struct vector *) where;
3221     length = fixnum_value(vector->length);
3222     nwords = CEILING(length + 2, 2);
3223
3224     return nwords;
3225 }
3226
3227 static int
3228 scav_vector_double_float(lispobj *where, lispobj object)
3229 {
3230     struct vector *vector;
3231     int length, nwords;
3232
3233     vector = (struct vector *) where;
3234     length = fixnum_value(vector->length);
3235     nwords = CEILING(length * 2 + 2, 2);
3236
3237     return nwords;
3238 }
3239
3240 static lispobj
3241 trans_vector_double_float(lispobj object)
3242 {
3243     struct vector *vector;
3244     int length, nwords;
3245
3246     gc_assert(Pointerp(object));
3247
3248     vector = (struct vector *) PTR(object);
3249     length = fixnum_value(vector->length);
3250     nwords = CEILING(length * 2 + 2, 2);
3251
3252     return copy_large_unboxed_object(object, nwords);
3253 }
3254
3255 static int
3256 size_vector_double_float(lispobj *where)
3257 {
3258     struct vector *vector;
3259     int length, nwords;
3260
3261     vector = (struct vector *) where;
3262     length = fixnum_value(vector->length);
3263     nwords = CEILING(length * 2 + 2, 2);
3264
3265     return nwords;
3266 }
3267
3268 #ifdef type_SimpleArrayLongFloat
3269 static int
3270 scav_vector_long_float(lispobj *where, lispobj object)
3271 {
3272     struct vector *vector;
3273     int length, nwords;
3274
3275     vector = (struct vector *) where;
3276     length = fixnum_value(vector->length);
3277     nwords = CEILING(length * 3 + 2, 2);
3278
3279     return nwords;
3280 }
3281
3282 static lispobj
3283 trans_vector_long_float(lispobj object)
3284 {
3285     struct vector *vector;
3286     int length, nwords;
3287
3288     gc_assert(Pointerp(object));
3289
3290     vector = (struct vector *) PTR(object);
3291     length = fixnum_value(vector->length);
3292     nwords = CEILING(length * 3 + 2, 2);
3293
3294     return copy_large_unboxed_object(object, nwords);
3295 }
3296
3297 static int
3298 size_vector_long_float(lispobj *where)
3299 {
3300     struct vector *vector;
3301     int length, nwords;
3302
3303     vector = (struct vector *) where;
3304     length = fixnum_value(vector->length);
3305     nwords = CEILING(length * 3 + 2, 2);
3306
3307     return nwords;
3308 }
3309 #endif
3310
3311
3312 #ifdef type_SimpleArrayComplexSingleFloat
3313 static int
3314 scav_vector_complex_single_float(lispobj *where, lispobj object)
3315 {
3316     struct vector *vector;
3317     int length, nwords;
3318
3319     vector = (struct vector *) where;
3320     length = fixnum_value(vector->length);
3321     nwords = CEILING(length * 2 + 2, 2);
3322
3323     return nwords;
3324 }
3325
3326 static lispobj
3327 trans_vector_complex_single_float(lispobj object)
3328 {
3329     struct vector *vector;
3330     int length, nwords;
3331
3332     gc_assert(Pointerp(object));
3333
3334     vector = (struct vector *) PTR(object);
3335     length = fixnum_value(vector->length);
3336     nwords = CEILING(length * 2 + 2, 2);
3337
3338     return copy_large_unboxed_object(object, nwords);
3339 }
3340
3341 static int
3342 size_vector_complex_single_float(lispobj *where)
3343 {
3344     struct vector *vector;
3345     int length, nwords;
3346
3347     vector = (struct vector *) where;
3348     length = fixnum_value(vector->length);
3349     nwords = CEILING(length * 2 + 2, 2);
3350
3351     return nwords;
3352 }
3353 #endif
3354
3355 #ifdef type_SimpleArrayComplexDoubleFloat
3356 static int
3357 scav_vector_complex_double_float(lispobj *where, lispobj object)
3358 {
3359     struct vector *vector;
3360     int length, nwords;
3361
3362     vector = (struct vector *) where;
3363     length = fixnum_value(vector->length);
3364     nwords = CEILING(length * 4 + 2, 2);
3365
3366     return nwords;
3367 }
3368
3369 static lispobj
3370 trans_vector_complex_double_float(lispobj object)
3371 {
3372     struct vector *vector;
3373     int length, nwords;
3374
3375     gc_assert(Pointerp(object));
3376
3377     vector = (struct vector *) PTR(object);
3378     length = fixnum_value(vector->length);
3379     nwords = CEILING(length * 4 + 2, 2);
3380
3381     return copy_large_unboxed_object(object, nwords);
3382 }
3383
3384 static int
3385 size_vector_complex_double_float(lispobj *where)
3386 {
3387     struct vector *vector;
3388     int length, nwords;
3389
3390     vector = (struct vector *) where;
3391     length = fixnum_value(vector->length);
3392     nwords = CEILING(length * 4 + 2, 2);
3393
3394     return nwords;
3395 }
3396 #endif
3397
3398
3399 #ifdef type_SimpleArrayComplexLongFloat
3400 static int
3401 scav_vector_complex_long_float(lispobj *where, lispobj object)
3402 {
3403     struct vector *vector;
3404     int length, nwords;
3405
3406     vector = (struct vector *) where;
3407     length = fixnum_value(vector->length);
3408     nwords = CEILING(length * 6 + 2, 2);
3409
3410     return nwords;
3411 }
3412
3413 static lispobj
3414 trans_vector_complex_long_float(lispobj object)
3415 {
3416     struct vector *vector;
3417     int length, nwords;
3418
3419     gc_assert(Pointerp(object));
3420
3421     vector = (struct vector *) PTR(object);
3422     length = fixnum_value(vector->length);
3423     nwords = CEILING(length * 6 + 2, 2);
3424
3425     return copy_large_unboxed_object(object, nwords);
3426 }
3427
3428 static int
3429 size_vector_complex_long_float(lispobj *where)
3430 {
3431     struct vector *vector;
3432     int length, nwords;
3433
3434     vector = (struct vector *) where;
3435     length = fixnum_value(vector->length);
3436     nwords = CEILING(length * 6 + 2, 2);
3437
3438     return nwords;
3439 }
3440 #endif
3441
3442 \f
3443 /*
3444  * weak pointers
3445  */
3446
3447 /* XX This is a hack adapted from cgc.c. These don't work too well with the
3448  * gencgc as a list of the weak pointers is maintained within the
3449  * objects which causes writes to the pages. A limited attempt is made
3450  * to avoid unnecessary writes, but this needs a re-think. */
3451
3452 #define WEAK_POINTER_NWORDS \
3453     CEILING((sizeof(struct weak_pointer) / sizeof(lispobj)), 2)
3454
3455 static int
3456 scav_weak_pointer(lispobj *where, lispobj object)
3457 {
3458     struct weak_pointer *wp = weak_pointers;
3459     /* Push the weak pointer onto the list of weak pointers.
3460      * Do I have to watch for duplicates? Originally this was
3461      * part of trans_weak_pointer but that didn't work in the
3462      * case where the WP was in a promoted region.
3463      */
3464
3465     /* Check whether it's already in the list. */
3466     while (wp != NULL) {
3467         if (wp == (struct weak_pointer*)where) {
3468             break;
3469         }
3470         wp = wp->next;
3471     }
3472     if (wp == NULL) {
3473         /* Add it to the start of the list. */
3474         wp = (struct weak_pointer*)where;
3475         if (wp->next != weak_pointers) {
3476             wp->next = weak_pointers;
3477         } else {
3478             /*SHOW("avoided write to weak pointer");*/
3479         }
3480         weak_pointers = wp;
3481     }
3482
3483     /* Do not let GC scavenge the value slot of the weak pointer.
3484      * (That is why it is a weak pointer.) */
3485
3486     return WEAK_POINTER_NWORDS;
3487 }
3488
3489 static lispobj
3490 trans_weak_pointer(lispobj object)
3491 {
3492     lispobj copy;
3493     /* struct weak_pointer *wp; */
3494
3495     gc_assert(Pointerp(object));
3496
3497 #if defined(DEBUG_WEAK)
3498     FSHOW((stderr, "Transporting weak pointer from 0x%08x\n", object));
3499 #endif
3500
3501     /* Need to remember where all the weak pointers are that have */
3502     /* been transported so they can be fixed up in a post-GC pass. */
3503
3504     copy = copy_object(object, WEAK_POINTER_NWORDS);
3505     /*  wp = (struct weak_pointer *) PTR(copy);*/
3506         
3507
3508     /* Push the weak pointer onto the list of weak pointers. */
3509     /*  wp->next = weak_pointers;
3510      *  weak_pointers = wp;*/
3511
3512     return copy;
3513 }
3514
3515 static int
3516 size_weak_pointer(lispobj *where)
3517 {
3518     return WEAK_POINTER_NWORDS;
3519 }
3520
3521 void scan_weak_pointers(void)
3522 {
3523     struct weak_pointer *wp;
3524     for (wp = weak_pointers; wp != NULL; wp = wp->next) {
3525         lispobj value = wp->value;
3526         lispobj *first_pointer;
3527
3528         first_pointer = (lispobj *)PTR(value);
3529
3530         /*
3531         FSHOW((stderr, "/weak pointer at 0x%08x\n", (unsigned long) wp));
3532         FSHOW((stderr, "/value: 0x%08x\n", (unsigned long) value));
3533         */
3534
3535         if (Pointerp(value) && from_space_p(value)) {
3536             /* Now, we need to check whether the object has been forwarded. If
3537              * it has been, the weak pointer is still good and needs to be
3538              * updated. Otherwise, the weak pointer needs to be nil'ed
3539              * out. */
3540             if (first_pointer[0] == 0x01) {
3541                 wp->value = first_pointer[1];
3542             } else {
3543                 /* Break it. */
3544                 SHOW("broken");
3545                 wp->value = NIL;
3546                 wp->broken = T;
3547             }
3548         }
3549     }
3550 }
3551 \f
3552 /*
3553  * initialization
3554  */
3555
3556 static int
3557 scav_lose(lispobj *where, lispobj object)
3558 {
3559     lose("no scavenge function for object 0x%08x", (unsigned long) object);
3560     return 0; /* bogus return value to satisfy static type checking */
3561 }
3562
3563 static lispobj
3564 trans_lose(lispobj object)
3565 {
3566     lose("no transport function for object 0x%08x", (unsigned long) object);
3567     return NIL; /* bogus return value to satisfy static type checking */
3568 }
3569
3570 static int
3571 size_lose(lispobj *where)
3572 {
3573     lose("no size function for object at 0x%08x", (unsigned long) where);
3574     return 1; /* bogus return value to satisfy static type checking */
3575 }
3576
3577 static void
3578 gc_init_tables(void)
3579 {
3580     int i;
3581
3582     /* Set default value in all slots of scavenge table. */
3583     for (i = 0; i < 256; i++) { /* FIXME: bare constant length, ick! */
3584         scavtab[i] = scav_lose;
3585     }
3586
3587     /* For each type which can be selected by the low 3 bits of the tag
3588      * alone, set multiple entries in our 8-bit scavenge table (one for each
3589      * possible value of the high 5 bits). */
3590     for (i = 0; i < 32; i++) { /* FIXME: bare constant length, ick! */
3591         scavtab[type_EvenFixnum|(i<<3)] = scav_immediate;
3592         scavtab[type_FunctionPointer|(i<<3)] = scav_function_pointer;
3593         /* OtherImmediate0 */
3594         scavtab[type_ListPointer|(i<<3)] = scav_list_pointer;
3595         scavtab[type_OddFixnum|(i<<3)] = scav_immediate;
3596         scavtab[type_InstancePointer|(i<<3)] = scav_instance_pointer;
3597         /* OtherImmediate1 */
3598         scavtab[type_OtherPointer|(i<<3)] = scav_other_pointer;
3599     }
3600
3601     /* Other-pointer types (those selected by all eight bits of the tag) get
3602      * one entry each in the scavenge table. */
3603     scavtab[type_Bignum] = scav_unboxed;
3604     scavtab[type_Ratio] = scav_boxed;
3605     scavtab[type_SingleFloat] = scav_unboxed;
3606     scavtab[type_DoubleFloat] = scav_unboxed;
3607 #ifdef type_LongFloat
3608     scavtab[type_LongFloat] = scav_unboxed;
3609 #endif
3610     scavtab[type_Complex] = scav_boxed;
3611 #ifdef type_ComplexSingleFloat
3612     scavtab[type_ComplexSingleFloat] = scav_unboxed;
3613 #endif
3614 #ifdef type_ComplexDoubleFloat
3615     scavtab[type_ComplexDoubleFloat] = scav_unboxed;
3616 #endif
3617 #ifdef type_ComplexLongFloat
3618     scavtab[type_ComplexLongFloat] = scav_unboxed;
3619 #endif
3620     scavtab[type_SimpleArray] = scav_boxed;
3621     scavtab[type_SimpleString] = scav_string;
3622     scavtab[type_SimpleBitVector] = scav_vector_bit;
3623     scavtab[type_SimpleVector] = scav_vector;
3624     scavtab[type_SimpleArrayUnsignedByte2] = scav_vector_unsigned_byte_2;
3625     scavtab[type_SimpleArrayUnsignedByte4] = scav_vector_unsigned_byte_4;
3626     scavtab[type_SimpleArrayUnsignedByte8] = scav_vector_unsigned_byte_8;
3627     scavtab[type_SimpleArrayUnsignedByte16] = scav_vector_unsigned_byte_16;
3628     scavtab[type_SimpleArrayUnsignedByte32] = scav_vector_unsigned_byte_32;
3629 #ifdef type_SimpleArraySignedByte8
3630     scavtab[type_SimpleArraySignedByte8] = scav_vector_unsigned_byte_8;
3631 #endif
3632 #ifdef type_SimpleArraySignedByte16
3633     scavtab[type_SimpleArraySignedByte16] = scav_vector_unsigned_byte_16;
3634 #endif
3635 #ifdef type_SimpleArraySignedByte30
3636     scavtab[type_SimpleArraySignedByte30] = scav_vector_unsigned_byte_32;
3637 #endif
3638 #ifdef type_SimpleArraySignedByte32
3639     scavtab[type_SimpleArraySignedByte32] = scav_vector_unsigned_byte_32;
3640 #endif
3641     scavtab[type_SimpleArraySingleFloat] = scav_vector_single_float;
3642     scavtab[type_SimpleArrayDoubleFloat] = scav_vector_double_float;
3643 #ifdef type_SimpleArrayLongFloat
3644     scavtab[type_SimpleArrayLongFloat] = scav_vector_long_float;
3645 #endif
3646 #ifdef type_SimpleArrayComplexSingleFloat
3647     scavtab[type_SimpleArrayComplexSingleFloat] = scav_vector_complex_single_float;
3648 #endif
3649 #ifdef type_SimpleArrayComplexDoubleFloat
3650     scavtab[type_SimpleArrayComplexDoubleFloat] = scav_vector_complex_double_float;
3651 #endif
3652 #ifdef type_SimpleArrayComplexLongFloat
3653     scavtab[type_SimpleArrayComplexLongFloat] = scav_vector_complex_long_float;
3654 #endif
3655     scavtab[type_ComplexString] = scav_boxed;
3656     scavtab[type_ComplexBitVector] = scav_boxed;
3657     scavtab[type_ComplexVector] = scav_boxed;
3658     scavtab[type_ComplexArray] = scav_boxed;
3659     scavtab[type_CodeHeader] = scav_code_header;
3660     /*scavtab[type_FunctionHeader] = scav_function_header;*/
3661     /*scavtab[type_ClosureFunctionHeader] = scav_function_header;*/
3662     /*scavtab[type_ReturnPcHeader] = scav_return_pc_header;*/
3663 #ifdef __i386__
3664     scavtab[type_ClosureHeader] = scav_closure_header;
3665     scavtab[type_FuncallableInstanceHeader] = scav_closure_header;
3666     scavtab[type_ByteCodeFunction] = scav_closure_header;
3667     scavtab[type_ByteCodeClosure] = scav_closure_header;
3668 #else
3669     scavtab[type_ClosureHeader] = scav_boxed;
3670     scavtab[type_FuncallableInstanceHeader] = scav_boxed;
3671     scavtab[type_ByteCodeFunction] = scav_boxed;
3672     scavtab[type_ByteCodeClosure] = scav_boxed;
3673 #endif
3674     scavtab[type_ValueCellHeader] = scav_boxed;
3675     scavtab[type_SymbolHeader] = scav_boxed;
3676     scavtab[type_BaseChar] = scav_immediate;
3677     scavtab[type_Sap] = scav_unboxed;
3678     scavtab[type_UnboundMarker] = scav_immediate;
3679     scavtab[type_WeakPointer] = scav_weak_pointer;
3680     scavtab[type_InstanceHeader] = scav_boxed;
3681     scavtab[type_Fdefn] = scav_fdefn;
3682
3683     /* transport other table, initialized same way as scavtab */
3684     for (i = 0; i < 256; i++)
3685         transother[i] = trans_lose;
3686     transother[type_Bignum] = trans_unboxed;
3687     transother[type_Ratio] = trans_boxed;
3688     transother[type_SingleFloat] = trans_unboxed;
3689     transother[type_DoubleFloat] = trans_unboxed;
3690 #ifdef type_LongFloat
3691     transother[type_LongFloat] = trans_unboxed;
3692 #endif
3693     transother[type_Complex] = trans_boxed;
3694 #ifdef type_ComplexSingleFloat
3695     transother[type_ComplexSingleFloat] = trans_unboxed;
3696 #endif
3697 #ifdef type_ComplexDoubleFloat
3698     transother[type_ComplexDoubleFloat] = trans_unboxed;
3699 #endif
3700 #ifdef type_ComplexLongFloat
3701     transother[type_ComplexLongFloat] = trans_unboxed;
3702 #endif
3703     transother[type_SimpleArray] = trans_boxed_large;
3704     transother[type_SimpleString] = trans_string;
3705     transother[type_SimpleBitVector] = trans_vector_bit;
3706     transother[type_SimpleVector] = trans_vector;
3707     transother[type_SimpleArrayUnsignedByte2] = trans_vector_unsigned_byte_2;
3708     transother[type_SimpleArrayUnsignedByte4] = trans_vector_unsigned_byte_4;
3709     transother[type_SimpleArrayUnsignedByte8] = trans_vector_unsigned_byte_8;
3710     transother[type_SimpleArrayUnsignedByte16] = trans_vector_unsigned_byte_16;
3711     transother[type_SimpleArrayUnsignedByte32] = trans_vector_unsigned_byte_32;
3712 #ifdef type_SimpleArraySignedByte8
3713     transother[type_SimpleArraySignedByte8] = trans_vector_unsigned_byte_8;
3714 #endif
3715 #ifdef type_SimpleArraySignedByte16
3716     transother[type_SimpleArraySignedByte16] = trans_vector_unsigned_byte_16;
3717 #endif
3718 #ifdef type_SimpleArraySignedByte30
3719     transother[type_SimpleArraySignedByte30] = trans_vector_unsigned_byte_32;
3720 #endif
3721 #ifdef type_SimpleArraySignedByte32
3722     transother[type_SimpleArraySignedByte32] = trans_vector_unsigned_byte_32;
3723 #endif
3724     transother[type_SimpleArraySingleFloat] = trans_vector_single_float;
3725     transother[type_SimpleArrayDoubleFloat] = trans_vector_double_float;
3726 #ifdef type_SimpleArrayLongFloat
3727     transother[type_SimpleArrayLongFloat] = trans_vector_long_float;
3728 #endif
3729 #ifdef type_SimpleArrayComplexSingleFloat
3730     transother[type_SimpleArrayComplexSingleFloat] = trans_vector_complex_single_float;
3731 #endif
3732 #ifdef type_SimpleArrayComplexDoubleFloat
3733     transother[type_SimpleArrayComplexDoubleFloat] = trans_vector_complex_double_float;
3734 #endif
3735 #ifdef type_SimpleArrayComplexLongFloat
3736     transother[type_SimpleArrayComplexLongFloat] = trans_vector_complex_long_float;
3737 #endif
3738     transother[type_ComplexString] = trans_boxed;
3739     transother[type_ComplexBitVector] = trans_boxed;
3740     transother[type_ComplexVector] = trans_boxed;
3741     transother[type_ComplexArray] = trans_boxed;
3742     transother[type_CodeHeader] = trans_code_header;
3743     transother[type_FunctionHeader] = trans_function_header;
3744     transother[type_ClosureFunctionHeader] = trans_function_header;
3745     transother[type_ReturnPcHeader] = trans_return_pc_header;
3746     transother[type_ClosureHeader] = trans_boxed;
3747     transother[type_FuncallableInstanceHeader] = trans_boxed;
3748     transother[type_ByteCodeFunction] = trans_boxed;
3749     transother[type_ByteCodeClosure] = trans_boxed;
3750     transother[type_ValueCellHeader] = trans_boxed;
3751     transother[type_SymbolHeader] = trans_boxed;
3752     transother[type_BaseChar] = trans_immediate;
3753     transother[type_Sap] = trans_unboxed;
3754     transother[type_UnboundMarker] = trans_immediate;
3755     transother[type_WeakPointer] = trans_weak_pointer;
3756     transother[type_InstanceHeader] = trans_boxed;
3757     transother[type_Fdefn] = trans_boxed;
3758
3759     /* size table, initialized the same way as scavtab */
3760     for (i = 0; i < 256; i++)
3761         sizetab[i] = size_lose;
3762     for (i = 0; i < 32; i++) {
3763         sizetab[type_EvenFixnum|(i<<3)] = size_immediate;
3764         sizetab[type_FunctionPointer|(i<<3)] = size_pointer;
3765         /* OtherImmediate0 */
3766         sizetab[type_ListPointer|(i<<3)] = size_pointer;
3767         sizetab[type_OddFixnum|(i<<3)] = size_immediate;
3768         sizetab[type_InstancePointer|(i<<3)] = size_pointer;
3769         /* OtherImmediate1 */
3770         sizetab[type_OtherPointer|(i<<3)] = size_pointer;
3771     }
3772     sizetab[type_Bignum] = size_unboxed;
3773     sizetab[type_Ratio] = size_boxed;
3774     sizetab[type_SingleFloat] = size_unboxed;
3775     sizetab[type_DoubleFloat] = size_unboxed;
3776 #ifdef type_LongFloat
3777     sizetab[type_LongFloat] = size_unboxed;
3778 #endif
3779     sizetab[type_Complex] = size_boxed;
3780 #ifdef type_ComplexSingleFloat
3781     sizetab[type_ComplexSingleFloat] = size_unboxed;
3782 #endif
3783 #ifdef type_ComplexDoubleFloat
3784     sizetab[type_ComplexDoubleFloat] = size_unboxed;
3785 #endif
3786 #ifdef type_ComplexLongFloat
3787     sizetab[type_ComplexLongFloat] = size_unboxed;
3788 #endif
3789     sizetab[type_SimpleArray] = size_boxed;
3790     sizetab[type_SimpleString] = size_string;
3791     sizetab[type_SimpleBitVector] = size_vector_bit;
3792     sizetab[type_SimpleVector] = size_vector;
3793     sizetab[type_SimpleArrayUnsignedByte2] = size_vector_unsigned_byte_2;
3794     sizetab[type_SimpleArrayUnsignedByte4] = size_vector_unsigned_byte_4;
3795     sizetab[type_SimpleArrayUnsignedByte8] = size_vector_unsigned_byte_8;
3796     sizetab[type_SimpleArrayUnsignedByte16] = size_vector_unsigned_byte_16;
3797     sizetab[type_SimpleArrayUnsignedByte32] = size_vector_unsigned_byte_32;
3798 #ifdef type_SimpleArraySignedByte8
3799     sizetab[type_SimpleArraySignedByte8] = size_vector_unsigned_byte_8;
3800 #endif
3801 #ifdef type_SimpleArraySignedByte16
3802     sizetab[type_SimpleArraySignedByte16] = size_vector_unsigned_byte_16;
3803 #endif
3804 #ifdef type_SimpleArraySignedByte30
3805     sizetab[type_SimpleArraySignedByte30] = size_vector_unsigned_byte_32;
3806 #endif
3807 #ifdef type_SimpleArraySignedByte32
3808     sizetab[type_SimpleArraySignedByte32] = size_vector_unsigned_byte_32;
3809 #endif
3810     sizetab[type_SimpleArraySingleFloat] = size_vector_single_float;
3811     sizetab[type_SimpleArrayDoubleFloat] = size_vector_double_float;
3812 #ifdef type_SimpleArrayLongFloat
3813     sizetab[type_SimpleArrayLongFloat] = size_vector_long_float;
3814 #endif
3815 #ifdef type_SimpleArrayComplexSingleFloat
3816     sizetab[type_SimpleArrayComplexSingleFloat] = size_vector_complex_single_float;
3817 #endif
3818 #ifdef type_SimpleArrayComplexDoubleFloat
3819     sizetab[type_SimpleArrayComplexDoubleFloat] = size_vector_complex_double_float;
3820 #endif
3821 #ifdef type_SimpleArrayComplexLongFloat
3822     sizetab[type_SimpleArrayComplexLongFloat] = size_vector_complex_long_float;
3823 #endif
3824     sizetab[type_ComplexString] = size_boxed;
3825     sizetab[type_ComplexBitVector] = size_boxed;
3826     sizetab[type_ComplexVector] = size_boxed;
3827     sizetab[type_ComplexArray] = size_boxed;
3828     sizetab[type_CodeHeader] = size_code_header;
3829 #if 0
3830     /* We shouldn't see these, so just lose if it happens. */
3831     sizetab[type_FunctionHeader] = size_function_header;
3832     sizetab[type_ClosureFunctionHeader] = size_function_header;
3833     sizetab[type_ReturnPcHeader] = size_return_pc_header;
3834 #endif
3835     sizetab[type_ClosureHeader] = size_boxed;
3836     sizetab[type_FuncallableInstanceHeader] = size_boxed;
3837     sizetab[type_ValueCellHeader] = size_boxed;
3838     sizetab[type_SymbolHeader] = size_boxed;
3839     sizetab[type_BaseChar] = size_immediate;
3840     sizetab[type_Sap] = size_unboxed;
3841     sizetab[type_UnboundMarker] = size_immediate;
3842     sizetab[type_WeakPointer] = size_weak_pointer;
3843     sizetab[type_InstanceHeader] = size_boxed;
3844     sizetab[type_Fdefn] = size_boxed;
3845 }
3846 \f
3847 /* Scan an area looking for an object which encloses the given pointer.
3848  * Return the object start on success or NULL on failure. */
3849 static lispobj *
3850 search_space(lispobj *start, size_t words, lispobj *pointer)
3851 {
3852     while (words > 0) {
3853         size_t count = 1;
3854         lispobj thing = *start;
3855
3856         /* If thing is an immediate then this is a cons */
3857         if (Pointerp(thing)
3858             || ((thing & 3) == 0) /* fixnum */
3859             || (TypeOf(thing) == type_BaseChar)
3860             || (TypeOf(thing) == type_UnboundMarker))
3861             count = 2;
3862         else
3863             count = (sizetab[TypeOf(thing)])(start);
3864
3865         /* Check whether the pointer is within this object? */
3866         if ((pointer >= start) && (pointer < (start+count))) {
3867             /* found it! */
3868             /*FSHOW((stderr,"/found %x in %x %x\n", pointer, start, thing));*/
3869             return(start);
3870         }
3871
3872         /* Round up the count */
3873         count = CEILING(count,2);
3874
3875         start += count;
3876         words -= count;
3877     }
3878     return (NULL);
3879 }
3880
3881 static lispobj*
3882 search_read_only_space(lispobj *pointer)
3883 {
3884     lispobj* start = (lispobj*)READ_ONLY_SPACE_START;
3885     lispobj* end = (lispobj*)SymbolValue(READ_ONLY_SPACE_FREE_POINTER);
3886     if ((pointer < start) || (pointer >= end))
3887         return NULL;
3888     return (search_space(start, (pointer+2)-start, pointer));
3889 }
3890
3891 static lispobj *
3892 search_static_space(lispobj *pointer)
3893 {
3894     lispobj* start = (lispobj*)STATIC_SPACE_START;
3895     lispobj* end = (lispobj*)SymbolValue(STATIC_SPACE_FREE_POINTER);
3896     if ((pointer < start) || (pointer >= end))
3897         return NULL;
3898     return (search_space(start, (pointer+2)-start, pointer));
3899 }
3900
3901 /* a faster version for searching the dynamic space. This will work even
3902  * if the object is in a current allocation region. */
3903 lispobj *
3904 search_dynamic_space(lispobj *pointer)
3905 {
3906     int  page_index = find_page_index(pointer);
3907     lispobj *start;
3908
3909     /* Address may be invalid - do some checks. */
3910     if ((page_index == -1) || (page_table[page_index].allocated == FREE_PAGE))
3911         return NULL;
3912     start = (lispobj *)((void *)page_address(page_index)
3913                         + page_table[page_index].first_object_offset);
3914     return (search_space(start, (pointer+2)-start, pointer));
3915 }
3916
3917 /* FIXME: There is a strong family resemblance between this function
3918  * and the function of the same name in purify.c. Would it be possible
3919  * to implement them as exactly the same function? */
3920 static int
3921 valid_dynamic_space_pointer(lispobj *pointer)
3922 {
3923     lispobj *start_addr;
3924
3925     /* Find the object start address */
3926     if ((start_addr = search_dynamic_space(pointer)) == NULL) {
3927         return 0;
3928     }
3929
3930     /* We need to allow raw pointers into Code objects for return
3931      * addresses. This will also pickup pointers to functions in code
3932      * objects. */
3933     if (TypeOf(*start_addr) == type_CodeHeader) {
3934         /* X Could do some further checks here. */
3935         return 1;
3936     }
3937
3938     /* If it's not a return address then it needs to be a valid Lisp
3939      * pointer. */
3940     if (!Pointerp((lispobj)pointer)) {
3941         return 0;
3942     }
3943
3944     /* Check that the object pointed to is consistent with the pointer
3945      * low tag. */
3946     switch (LowtagOf((lispobj)pointer)) {
3947     case type_FunctionPointer:
3948         /* Start_addr should be the enclosing code object, or a closure
3949            header. */
3950         switch (TypeOf(*start_addr)) {
3951         case type_CodeHeader:
3952             /* This case is probably caught above. */
3953             break;
3954         case type_ClosureHeader:
3955         case type_FuncallableInstanceHeader:
3956         case type_ByteCodeFunction:
3957         case type_ByteCodeClosure:
3958             if ((unsigned)pointer !=
3959                 ((unsigned)start_addr+type_FunctionPointer)) {
3960                 if (gencgc_verbose)
3961                     FSHOW((stderr,
3962                            "/Wf2: %x %x %x\n",
3963                            pointer, start_addr, *start_addr));
3964                 return 0;
3965             }
3966             break;
3967         default:
3968             if (gencgc_verbose)
3969                 FSHOW((stderr,
3970                        "/Wf3: %x %x %x\n",
3971                        pointer, start_addr, *start_addr));
3972             return 0;
3973         }
3974         break;
3975     case type_ListPointer:
3976         if ((unsigned)pointer !=
3977             ((unsigned)start_addr+type_ListPointer)) {
3978             if (gencgc_verbose)
3979                 FSHOW((stderr,
3980                        "/Wl1: %x %x %x\n",
3981                        pointer, start_addr, *start_addr));
3982             return 0;
3983         }
3984         /* Is it plausible cons? */
3985         if ((Pointerp(start_addr[0])
3986             || ((start_addr[0] & 3) == 0) /* fixnum */
3987             || (TypeOf(start_addr[0]) == type_BaseChar)
3988             || (TypeOf(start_addr[0]) == type_UnboundMarker))
3989            && (Pointerp(start_addr[1])
3990                || ((start_addr[1] & 3) == 0) /* fixnum */
3991                || (TypeOf(start_addr[1]) == type_BaseChar)
3992                || (TypeOf(start_addr[1]) == type_UnboundMarker)))
3993             break;
3994         else {
3995             if (gencgc_verbose)
3996                 FSHOW((stderr,
3997                        "/Wl2: %x %x %x\n",
3998                        pointer, start_addr, *start_addr));
3999             return 0;
4000         }
4001     case type_InstancePointer:
4002         if ((unsigned)pointer !=
4003             ((unsigned)start_addr+type_InstancePointer)) {
4004             if (gencgc_verbose)
4005                 FSHOW((stderr,
4006                        "/Wi1: %x %x %x\n",
4007                        pointer, start_addr, *start_addr));
4008             return 0;
4009         }
4010         if (TypeOf(start_addr[0]) != type_InstanceHeader) {
4011             if (gencgc_verbose)
4012                 FSHOW((stderr,
4013                        "/Wi2: %x %x %x\n",
4014                        pointer, start_addr, *start_addr));
4015             return 0;
4016         }
4017         break;
4018     case type_OtherPointer:
4019         if ((unsigned)pointer !=
4020             ((int)start_addr+type_OtherPointer)) {
4021             if (gencgc_verbose)
4022                 FSHOW((stderr,
4023                        "/Wo1: %x %x %x\n",
4024                        pointer, start_addr, *start_addr));
4025             return 0;
4026         }
4027         /* Is it plausible?  Not a cons. X should check the headers. */
4028         if (Pointerp(start_addr[0]) || ((start_addr[0] & 3) == 0)) {
4029             if (gencgc_verbose)
4030                 FSHOW((stderr,
4031                        "/Wo2: %x %x %x\n",
4032                        pointer, start_addr, *start_addr));
4033             return 0;
4034         }
4035         switch (TypeOf(start_addr[0])) {
4036         case type_UnboundMarker:
4037         case type_BaseChar:
4038             if (gencgc_verbose)
4039                 FSHOW((stderr,
4040                        "*Wo3: %x %x %x\n",
4041                        pointer, start_addr, *start_addr));
4042             return 0;
4043
4044             /* only pointed to by function pointers? */
4045         case type_ClosureHeader:
4046         case type_FuncallableInstanceHeader:
4047         case type_ByteCodeFunction:
4048         case type_ByteCodeClosure:
4049             if (gencgc_verbose)
4050                 FSHOW((stderr,
4051                        "*Wo4: %x %x %x\n",
4052                        pointer, start_addr, *start_addr));
4053             return 0;
4054
4055         case type_InstanceHeader:
4056             if (gencgc_verbose)
4057                 FSHOW((stderr,
4058                        "*Wo5: %x %x %x\n",
4059                        pointer, start_addr, *start_addr));
4060             return 0;
4061
4062             /* the valid other immediate pointer objects */
4063         case type_SimpleVector:
4064         case type_Ratio:
4065         case type_Complex:
4066 #ifdef type_ComplexSingleFloat
4067         case type_ComplexSingleFloat:
4068 #endif
4069 #ifdef type_ComplexDoubleFloat
4070         case type_ComplexDoubleFloat:
4071 #endif
4072 #ifdef type_ComplexLongFloat
4073         case type_ComplexLongFloat:
4074 #endif
4075         case type_SimpleArray:
4076         case type_ComplexString:
4077         case type_ComplexBitVector:
4078         case type_ComplexVector:
4079         case type_ComplexArray:
4080         case type_ValueCellHeader:
4081         case type_SymbolHeader:
4082         case type_Fdefn:
4083         case type_CodeHeader:
4084         case type_Bignum:
4085         case type_SingleFloat:
4086         case type_DoubleFloat:
4087 #ifdef type_LongFloat
4088         case type_LongFloat:
4089 #endif
4090         case type_SimpleString:
4091         case type_SimpleBitVector:
4092         case type_SimpleArrayUnsignedByte2:
4093         case type_SimpleArrayUnsignedByte4:
4094         case type_SimpleArrayUnsignedByte8:
4095         case type_SimpleArrayUnsignedByte16:
4096         case type_SimpleArrayUnsignedByte32:
4097 #ifdef type_SimpleArraySignedByte8
4098         case type_SimpleArraySignedByte8:
4099 #endif
4100 #ifdef type_SimpleArraySignedByte16
4101         case type_SimpleArraySignedByte16:
4102 #endif
4103 #ifdef type_SimpleArraySignedByte30
4104         case type_SimpleArraySignedByte30:
4105 #endif
4106 #ifdef type_SimpleArraySignedByte32
4107         case type_SimpleArraySignedByte32:
4108 #endif
4109         case type_SimpleArraySingleFloat:
4110         case type_SimpleArrayDoubleFloat:
4111 #ifdef type_SimpleArrayLongFloat
4112         case type_SimpleArrayLongFloat:
4113 #endif
4114 #ifdef type_SimpleArrayComplexSingleFloat
4115         case type_SimpleArrayComplexSingleFloat:
4116 #endif
4117 #ifdef type_SimpleArrayComplexDoubleFloat
4118         case type_SimpleArrayComplexDoubleFloat:
4119 #endif
4120 #ifdef type_SimpleArrayComplexLongFloat
4121         case type_SimpleArrayComplexLongFloat:
4122 #endif
4123         case type_Sap:
4124         case type_WeakPointer:
4125             break;
4126
4127         default:
4128             if (gencgc_verbose)
4129                 FSHOW((stderr,
4130                        "/Wo6: %x %x %x\n",
4131                        pointer, start_addr, *start_addr));
4132             return 0;
4133         }
4134         break;
4135     default:
4136         if (gencgc_verbose)
4137             FSHOW((stderr,
4138                    "*W?: %x %x %x\n",
4139                    pointer, start_addr, *start_addr));
4140         return 0;
4141     }
4142
4143     /* looks good */
4144     return 1;
4145 }
4146
4147 /* Adjust large bignum and vector objects. This will adjust the allocated
4148  * region if the size has shrunk, and move unboxed objects into unboxed
4149  * pages. The pages are not promoted here, and the promoted region is not
4150  * added to the new_regions; this is really only designed to be called from
4151  * preserve_pointer. Shouldn't fail if this is missed, just may delay the
4152  * moving of objects to unboxed pages, and the freeing of pages. */
4153 static void
4154 maybe_adjust_large_object(lispobj *where)
4155 {
4156     int first_page;
4157     int nwords;
4158
4159     int remaining_bytes;
4160     int next_page;
4161     int bytes_freed;
4162     int old_bytes_used;
4163
4164     int boxed;
4165
4166     /* Check whether it's a vector or bignum object. */
4167     switch (TypeOf(where[0])) {
4168     case type_SimpleVector:
4169         boxed = BOXED_PAGE;
4170         break;
4171     case type_Bignum:
4172     case type_SimpleString:
4173     case type_SimpleBitVector:
4174     case type_SimpleArrayUnsignedByte2:
4175     case type_SimpleArrayUnsignedByte4:
4176     case type_SimpleArrayUnsignedByte8:
4177     case type_SimpleArrayUnsignedByte16:
4178     case type_SimpleArrayUnsignedByte32:
4179 #ifdef type_SimpleArraySignedByte8
4180     case type_SimpleArraySignedByte8:
4181 #endif
4182 #ifdef type_SimpleArraySignedByte16
4183     case type_SimpleArraySignedByte16:
4184 #endif
4185 #ifdef type_SimpleArraySignedByte30
4186     case type_SimpleArraySignedByte30:
4187 #endif
4188 #ifdef type_SimpleArraySignedByte32
4189     case type_SimpleArraySignedByte32:
4190 #endif
4191     case type_SimpleArraySingleFloat:
4192     case type_SimpleArrayDoubleFloat:
4193 #ifdef type_SimpleArrayLongFloat
4194     case type_SimpleArrayLongFloat:
4195 #endif
4196 #ifdef type_SimpleArrayComplexSingleFloat
4197     case type_SimpleArrayComplexSingleFloat:
4198 #endif
4199 #ifdef type_SimpleArrayComplexDoubleFloat
4200     case type_SimpleArrayComplexDoubleFloat:
4201 #endif
4202 #ifdef type_SimpleArrayComplexLongFloat
4203     case type_SimpleArrayComplexLongFloat:
4204 #endif
4205         boxed = UNBOXED_PAGE;
4206         break;
4207     default:
4208         return;
4209     }
4210
4211     /* Find its current size. */
4212     nwords = (sizetab[TypeOf(where[0])])(where);
4213
4214     first_page = find_page_index((void *)where);
4215     gc_assert(first_page >= 0);
4216
4217     /* Note: Any page write-protection must be removed, else a later
4218      * scavenge_newspace may incorrectly not scavenge these pages.
4219      * This would not be necessary if they are added to the new areas,
4220      * but lets do it for them all (they'll probably be written
4221      * anyway?). */
4222
4223     gc_assert(page_table[first_page].first_object_offset == 0);
4224
4225     next_page = first_page;
4226     remaining_bytes = nwords*4;
4227     while (remaining_bytes > 4096) {
4228         gc_assert(page_table[next_page].gen == from_space);
4229         gc_assert((page_table[next_page].allocated == BOXED_PAGE)
4230                   || (page_table[next_page].allocated == UNBOXED_PAGE));
4231         gc_assert(page_table[next_page].large_object);
4232         gc_assert(page_table[next_page].first_object_offset ==
4233                   -4096*(next_page-first_page));
4234         gc_assert(page_table[next_page].bytes_used == 4096);
4235
4236         page_table[next_page].allocated = boxed;
4237
4238         /* Shouldn't be write-protected at this stage. Essential that the
4239          * pages aren't. */
4240         gc_assert(!page_table[next_page].write_protected);
4241         remaining_bytes -= 4096;
4242         next_page++;
4243     }
4244
4245     /* Now only one page remains, but the object may have shrunk so
4246      * there may be more unused pages which will be freed. */
4247
4248     /* Object may have shrunk but shouldn't have grown - check. */
4249     gc_assert(page_table[next_page].bytes_used >= remaining_bytes);
4250
4251     page_table[next_page].allocated = boxed;
4252     gc_assert(page_table[next_page].allocated ==
4253               page_table[first_page].allocated);
4254
4255     /* Adjust the bytes_used. */
4256     old_bytes_used = page_table[next_page].bytes_used;
4257     page_table[next_page].bytes_used = remaining_bytes;
4258
4259     bytes_freed = old_bytes_used - remaining_bytes;
4260
4261     /* Free any remaining pages; needs care. */
4262     next_page++;
4263     while ((old_bytes_used == 4096) &&
4264            (page_table[next_page].gen == from_space) &&
4265            ((page_table[next_page].allocated == UNBOXED_PAGE)
4266             || (page_table[next_page].allocated == BOXED_PAGE)) &&
4267            page_table[next_page].large_object &&
4268            (page_table[next_page].first_object_offset ==
4269             -(next_page - first_page)*4096)) {
4270         /* It checks out OK, free the page. We don't need to both zeroing
4271          * pages as this should have been done before shrinking the
4272          * object. These pages shouldn't be write protected as they
4273          * should be zero filled. */
4274         gc_assert(page_table[next_page].write_protected == 0);
4275
4276         old_bytes_used = page_table[next_page].bytes_used;
4277         page_table[next_page].allocated = FREE_PAGE;
4278         page_table[next_page].bytes_used = 0;
4279         bytes_freed += old_bytes_used;
4280         next_page++;
4281     }
4282
4283     if ((bytes_freed > 0) && gencgc_verbose)
4284         FSHOW((stderr, "/adjust_large_object freed %d\n", bytes_freed));
4285
4286     generations[from_space].bytes_allocated -= bytes_freed;
4287     bytes_allocated -= bytes_freed;
4288
4289     return;
4290 }
4291
4292 /* Take a possible pointer to a list object and mark the page_table
4293  * so that it will not need changing during a GC.
4294  *
4295  * This involves locating the page it points to, then backing up to
4296  * the first page that has its first object start at offset 0, and
4297  * then marking all pages dont_move from the first until a page that ends
4298  * by being full, or having free gen.
4299  *
4300  * This ensures that objects spanning pages are not broken.
4301  *
4302  * It is assumed that all the page static flags have been cleared at
4303  * the start of a GC.
4304  *
4305  * It is also assumed that the current gc_alloc region has been flushed and
4306  * the tables updated. */
4307 static void
4308 preserve_pointer(void *addr)
4309 {
4310     int addr_page_index = find_page_index(addr);
4311     int first_page;
4312     int i;
4313     unsigned region_allocation;
4314
4315     /* Address is quite likely to have been invalid - do some checks. */
4316     if ((addr_page_index == -1)
4317         || (page_table[addr_page_index].allocated == FREE_PAGE)
4318         || (page_table[addr_page_index].bytes_used == 0)
4319         || (page_table[addr_page_index].gen != from_space)
4320         /* Skip if already marked dont_move */
4321         || (page_table[addr_page_index].dont_move != 0))
4322         return;
4323
4324     region_allocation = page_table[addr_page_index].allocated;
4325
4326     /* Check the offset within the page.
4327      *
4328      * FIXME: The mask should have a symbolic name, and ideally should
4329      * be derived from page size instead of hardwired to 0xfff.
4330      * (Also fix other uses of 0xfff, elsewhere.) */
4331     if (((unsigned)addr & 0xfff) > page_table[addr_page_index].bytes_used)
4332         return;
4333
4334     if (enable_pointer_filter && !valid_dynamic_space_pointer(addr))
4335         return;
4336
4337     /* Work backwards to find a page with a first_object_offset of 0.
4338      * The pages should be contiguous with all bytes used in the same
4339      * gen. Assumes the first_object_offset is negative or zero. */
4340     first_page = addr_page_index;
4341     while (page_table[first_page].first_object_offset != 0) {
4342         first_page--;
4343         /* Do some checks. */
4344         gc_assert(page_table[first_page].bytes_used == 4096);
4345         gc_assert(page_table[first_page].gen == from_space);
4346         gc_assert(page_table[first_page].allocated == region_allocation);
4347     }
4348
4349     /* Adjust any large objects before promotion as they won't be copied
4350      * after promotion. */
4351     if (page_table[first_page].large_object) {
4352         maybe_adjust_large_object(page_address(first_page));
4353         /* If a large object has shrunk then addr may now point to a free
4354          * area in which case it's ignored here. Note it gets through the
4355          * valid pointer test above because the tail looks like conses. */
4356         if ((page_table[addr_page_index].allocated == FREE_PAGE)
4357             || (page_table[addr_page_index].bytes_used == 0)
4358             /* Check the offset within the page. */
4359             || (((unsigned)addr & 0xfff)
4360                 > page_table[addr_page_index].bytes_used)) {
4361             FSHOW((stderr,
4362                    "weird? ignore ptr 0x%x to freed area of large object\n",
4363                    addr));
4364             return;
4365         }
4366         /* It may have moved to unboxed pages. */
4367         region_allocation = page_table[first_page].allocated;
4368     }
4369
4370     /* Now work forward until the end of this contiguous area is found,
4371      * marking all pages as dont_move. */
4372     for (i = first_page; ;i++) {
4373         gc_assert(page_table[i].allocated == region_allocation);
4374
4375         /* Mark the page static. */
4376         page_table[i].dont_move = 1;
4377
4378         /* Move the page to the new_space. XX I'd rather not do this but
4379          * the GC logic is not quite able to copy with the static pages
4380          * remaining in the from space. This also requires the generation
4381          * bytes_allocated counters be updated. */
4382         page_table[i].gen = new_space;
4383         generations[new_space].bytes_allocated += page_table[i].bytes_used;
4384         generations[from_space].bytes_allocated -= page_table[i].bytes_used;
4385
4386         /* It is essential that the pages are not write protected as they
4387          * may have pointers into the old-space which need scavenging. They
4388          * shouldn't be write protected at this stage. */
4389         gc_assert(!page_table[i].write_protected);
4390
4391         /* Check whether this is the last page in this contiguous block.. */
4392         if ((page_table[i].bytes_used < 4096)
4393             /* ..or it is 4096 and is the last in the block */
4394             || (page_table[i+1].allocated == FREE_PAGE)
4395             || (page_table[i+1].bytes_used == 0) /* next page free */
4396             || (page_table[i+1].gen != from_space) /* diff. gen */
4397             || (page_table[i+1].first_object_offset == 0))
4398             break;
4399     }
4400
4401     /* Check that the page is now static. */
4402     gc_assert(page_table[addr_page_index].dont_move != 0);
4403
4404     return;
4405 }
4406
4407 #ifdef CONTROL_STACKS
4408 /* Scavenge the thread stack conservative roots. */
4409 static void
4410 scavenge_thread_stacks(void)
4411 {
4412     lispobj thread_stacks = SymbolValue(CONTROL_STACKS);
4413     int type = TypeOf(thread_stacks);
4414
4415     if (LowtagOf(thread_stacks) == type_OtherPointer) {
4416         struct vector *vector = (struct vector *) PTR(thread_stacks);
4417         int length, i;
4418         if (TypeOf(vector->header) != type_SimpleVector)
4419             return;
4420         length = fixnum_value(vector->length);
4421         for (i = 0; i < length; i++) {
4422             lispobj stack_obj = vector->data[i];
4423             if (LowtagOf(stack_obj) == type_OtherPointer) {
4424                 struct vector *stack = (struct vector *) PTR(stack_obj);
4425                 int vector_length;
4426                 if (TypeOf(stack->header) !=
4427                     type_SimpleArrayUnsignedByte32) {
4428                     return;
4429                 }
4430                 vector_length = fixnum_value(stack->length);
4431                 if ((gencgc_verbose > 1) && (vector_length <= 0))
4432                     FSHOW((stderr,
4433                            "/weird? control stack vector length %d\n",
4434                            vector_length));
4435                 if (vector_length > 0) {
4436                     lispobj *stack_pointer = (lispobj*)stack->data[0];
4437                     if ((stack_pointer < (lispobj *)CONTROL_STACK_START) ||
4438                         (stack_pointer > (lispobj *)CONTROL_STACK_END))
4439                         lose("invalid stack pointer %x",
4440                              (unsigned)stack_pointer);
4441                     if ((stack_pointer > (lispobj *)CONTROL_STACK_START) &&
4442                         (stack_pointer < (lispobj *)CONTROL_STACK_END)) {
4443                         /* FIXME: Ick!
4444                          *   (1) hardwired word length = 4; and as usual,
4445                          *       when fixing this, check for other places
4446                          *       with the same problem
4447                          *   (2) calling it 'length' suggests bytes;
4448                          *       perhaps 'size' instead? */
4449                         unsigned int length = ((unsigned)CONTROL_STACK_END -
4450                                                (unsigned)stack_pointer) / 4;
4451                         int j;
4452                         if (length >= vector_length) {
4453                             lose("invalid stack size %d >= vector length %d",
4454                                  length,
4455                                  vector_length);
4456                         }
4457                         if (gencgc_verbose > 1) {
4458                             FSHOW((stderr,
4459                                    "scavenging %d words of control stack %d of length %d words.\n",
4460                                     length, i, vector_length));
4461                         }
4462                         for (j = 0; j < length; j++) {
4463                             preserve_pointer((void *)stack->data[1+j]);
4464                         }
4465                     }
4466                 }
4467             }
4468         }
4469     }
4470 }
4471 #endif
4472
4473 \f
4474 /* If the given page is not write-protected, then scan it for pointers
4475  * to younger generations or the top temp. generation, if no
4476  * suspicious pointers are found then the page is write-protected.
4477  *
4478  * Care is taken to check for pointers to the current gc_alloc region
4479  * if it is a younger generation or the temp. generation. This frees
4480  * the caller from doing a gc_alloc_update_page_tables. Actually the
4481  * gc_alloc_generation does not need to be checked as this is only
4482  * called from scavenge_generation when the gc_alloc generation is
4483  * younger, so it just checks if there is a pointer to the current
4484  * region.
4485  *
4486  * We return 1 if the page was write-protected, else 0.
4487  */
4488 static int
4489 update_page_write_prot(int page)
4490 {
4491     int gen = page_table[page].gen;
4492     int j;
4493     int wp_it = 1;
4494     void **page_addr = (void **)page_address(page);
4495     int num_words = page_table[page].bytes_used / 4;
4496
4497     /* Shouldn't be a free page. */
4498     gc_assert(page_table[page].allocated != FREE_PAGE);
4499     gc_assert(page_table[page].bytes_used != 0);
4500
4501     /* Skip if it's already write-protected or an unboxed page. */
4502     if (page_table[page].write_protected
4503         || (page_table[page].allocated == UNBOXED_PAGE))
4504         return (0);
4505
4506     /* Scan the page for pointers to younger generations or the
4507      * top temp. generation. */
4508
4509     for (j = 0; j < num_words; j++) {
4510         void *ptr = *(page_addr+j);
4511         int index = find_page_index(ptr);
4512
4513         /* Check that it's in the dynamic space */
4514         if (index != -1)
4515             if (/* Does it point to a younger or the temp. generation? */
4516                 ((page_table[index].allocated != FREE_PAGE)
4517                  && (page_table[index].bytes_used != 0)
4518                  && ((page_table[index].gen < gen)
4519                      || (page_table[index].gen == NUM_GENERATIONS)))
4520
4521                 /* Or does it point within a current gc_alloc region? */
4522                 || ((boxed_region.start_addr <= ptr)
4523                     && (ptr <= boxed_region.free_pointer))
4524                 || ((unboxed_region.start_addr <= ptr)
4525                     && (ptr <= unboxed_region.free_pointer))) {
4526                 wp_it = 0;
4527                 break;
4528             }
4529     }
4530
4531     if (wp_it == 1) {
4532         /* Write-protect the page. */
4533         /*FSHOW((stderr, "/write-protecting page %d gen %d\n", page, gen));*/
4534
4535         os_protect((void *)page_addr,
4536                    4096,
4537                    OS_VM_PROT_READ|OS_VM_PROT_EXECUTE);
4538
4539         /* Note the page as protected in the page tables. */
4540         page_table[page].write_protected = 1;
4541     }
4542
4543     return (wp_it);
4544 }
4545
4546 /* Scavenge a generation.
4547  *
4548  * This will not resolve all pointers when generation is the new
4549  * space, as new objects may be added which are not check here - use
4550  * scavenge_newspace generation.
4551  *
4552  * Write-protected pages should not have any pointers to the
4553  * from_space so do need scavenging; thus write-protected pages are
4554  * not always scavenged. There is some code to check that these pages
4555  * are not written; but to check fully the write-protected pages need
4556  * to be scavenged by disabling the code to skip them.
4557  *
4558  * Under the current scheme when a generation is GCed the younger
4559  * generations will be empty. So, when a generation is being GCed it
4560  * is only necessary to scavenge the older generations for pointers
4561  * not the younger. So a page that does not have pointers to younger
4562  * generations does not need to be scavenged.
4563  *
4564  * The write-protection can be used to note pages that don't have
4565  * pointers to younger pages. But pages can be written without having
4566  * pointers to younger generations. After the pages are scavenged here
4567  * they can be scanned for pointers to younger generations and if
4568  * there are none the page can be write-protected.
4569  *
4570  * One complication is when the newspace is the top temp. generation.
4571  *
4572  * Enabling SC_GEN_CK scavenges the write-protected pages and checks
4573  * that none were written, which they shouldn't be as they should have
4574  * no pointers to younger generations. This breaks down for weak
4575  * pointers as the objects contain a link to the next and are written
4576  * if a weak pointer is scavenged. Still it's a useful check. */
4577 static void
4578 scavenge_generation(int generation)
4579 {
4580     int i;
4581     int num_wp = 0;
4582
4583 #define SC_GEN_CK 0
4584 #if SC_GEN_CK
4585     /* Clear the write_protected_cleared flags on all pages. */
4586     for (i = 0; i < NUM_PAGES; i++)
4587         page_table[i].write_protected_cleared = 0;
4588 #endif
4589
4590     for (i = 0; i < last_free_page; i++) {
4591         if ((page_table[i].allocated == BOXED_PAGE)
4592             && (page_table[i].bytes_used != 0)
4593             && (page_table[i].gen == generation)) {
4594             int last_page;
4595
4596             /* This should be the start of a contiguous block. */
4597             gc_assert(page_table[i].first_object_offset == 0);
4598
4599             /* We need to find the full extent of this contiguous
4600              * block in case objects span pages. */
4601
4602             /* Now work forward until the end of this contiguous area
4603              * is found. A small area is preferred as there is a
4604              * better chance of its pages being write-protected. */
4605             for (last_page = i; ;last_page++)
4606                 /* Check whether this is the last page in this contiguous
4607                  * block. */
4608                 if ((page_table[last_page].bytes_used < 4096)
4609                     /* Or it is 4096 and is the last in the block */
4610                     || (page_table[last_page+1].allocated != BOXED_PAGE)
4611                     || (page_table[last_page+1].bytes_used == 0)
4612                     || (page_table[last_page+1].gen != generation)
4613                     || (page_table[last_page+1].first_object_offset == 0))
4614                     break;
4615
4616             /* Do a limited check for write_protected pages. If all pages
4617              * are write_protected then there is no need to scavenge. */
4618             {
4619                 int j, all_wp = 1;
4620                 for (j = i; j <= last_page; j++)
4621                     if (page_table[j].write_protected == 0) {
4622                         all_wp = 0;
4623                         break;
4624                     }
4625 #if !SC_GEN_CK
4626                 if (all_wp == 0)
4627 #endif
4628                     {
4629                         scavenge(page_address(i), (page_table[last_page].bytes_used
4630                                                    + (last_page-i)*4096)/4);
4631
4632                         /* Now scan the pages and write protect those
4633                          * that don't have pointers to younger
4634                          * generations. */
4635                         if (enable_page_protection) {
4636                             for (j = i; j <= last_page; j++) {
4637                                 num_wp += update_page_write_prot(j);
4638                             }
4639                         }
4640                     }
4641             }
4642             i = last_page;
4643         }
4644     }
4645
4646     if ((gencgc_verbose > 1) && (num_wp != 0)) {
4647         FSHOW((stderr,
4648                "/write protected %d pages within generation %d\n",
4649                num_wp, generation));
4650     }
4651
4652 #if SC_GEN_CK
4653     /* Check that none of the write_protected pages in this generation
4654      * have been written to. */
4655     for (i = 0; i < NUM_PAGES; i++) {
4656         if ((page_table[i].allocation ! =FREE_PAGE)
4657             && (page_table[i].bytes_used != 0)
4658             && (page_table[i].gen == generation)
4659             && (page_table[i].write_protected_cleared != 0)) {
4660             FSHOW((stderr, "/scavenge_generation %d\n", generation));
4661             FSHOW((stderr,
4662                    "/page bytes_used=%d first_object_offset=%d dont_move=%d\n",
4663                     page_table[i].bytes_used,
4664                     page_table[i].first_object_offset,
4665                     page_table[i].dont_move));
4666             lose("write-protected page %d written to in scavenge_generation",
4667                  i);
4668         }
4669     }
4670 #endif
4671 }
4672
4673 \f
4674 /* Scavenge a newspace generation. As it is scavenged new objects may
4675  * be allocated to it; these will also need to be scavenged. This
4676  * repeats until there are no more objects unscavenged in the
4677  * newspace generation.
4678  *
4679  * To help improve the efficiency, areas written are recorded by
4680  * gc_alloc and only these scavenged. Sometimes a little more will be
4681  * scavenged, but this causes no harm. An easy check is done that the
4682  * scavenged bytes equals the number allocated in the previous
4683  * scavenge.
4684  *
4685  * Write-protected pages are not scanned except if they are marked
4686  * dont_move in which case they may have been promoted and still have
4687  * pointers to the from space.
4688  *
4689  * Write-protected pages could potentially be written by alloc however
4690  * to avoid having to handle re-scavenging of write-protected pages
4691  * gc_alloc does not write to write-protected pages.
4692  *
4693  * New areas of objects allocated are recorded alternatively in the two
4694  * new_areas arrays below. */
4695 static struct new_area new_areas_1[NUM_NEW_AREAS];
4696 static struct new_area new_areas_2[NUM_NEW_AREAS];
4697
4698 /* Do one full scan of the new space generation. This is not enough to
4699  * complete the job as new objects may be added to the generation in
4700  * the process which are not scavenged. */
4701 static void
4702 scavenge_newspace_generation_one_scan(int generation)
4703 {
4704     int i;
4705
4706     FSHOW((stderr,
4707            "/starting one full scan of newspace generation %d\n",
4708            generation));
4709
4710     for (i = 0; i < last_free_page; i++) {
4711         if ((page_table[i].allocated == BOXED_PAGE)
4712             && (page_table[i].bytes_used != 0)
4713             && (page_table[i].gen == generation)
4714             && ((page_table[i].write_protected == 0)
4715                 /* (This may be redundant as write_protected is now
4716                  * cleared before promotion.) */
4717                 || (page_table[i].dont_move == 1))) {
4718             int last_page;
4719
4720             /* The scavenge will start at the first_object_offset of page i.
4721              *
4722              * We need to find the full extent of this contiguous
4723              * block in case objects span pages.
4724              *
4725              * Now work forward until the end of this contiguous area
4726              * is found. A small area is preferred as there is a
4727              * better chance of its pages being write-protected. */
4728             for (last_page = i; ;last_page++) {
4729                 /* Check whether this is the last page in this
4730                  * contiguous block */
4731                 if ((page_table[last_page].bytes_used < 4096)
4732                     /* Or it is 4096 and is the last in the block */
4733                     || (page_table[last_page+1].allocated != BOXED_PAGE)
4734                     || (page_table[last_page+1].bytes_used == 0)
4735                     || (page_table[last_page+1].gen != generation)
4736                     || (page_table[last_page+1].first_object_offset == 0))
4737                     break;
4738             }
4739
4740             /* Do a limited check for write-protected pages. If all
4741              * pages are write-protected then no need to scavenge,
4742              * except if the pages are marked dont_move. */
4743             {
4744                 int j, all_wp = 1;
4745                 for (j = i; j <= last_page; j++)
4746                     if ((page_table[j].write_protected == 0)
4747                         || (page_table[j].dont_move != 0)) {
4748                         all_wp = 0;
4749                         break;
4750                     }
4751
4752                 if (!all_wp) {
4753                     int size;
4754
4755                     /* Calculate the size. */
4756                     if (last_page == i)
4757                         size = (page_table[last_page].bytes_used
4758                                 - page_table[i].first_object_offset)/4;
4759                     else
4760                         size = (page_table[last_page].bytes_used
4761                                 + (last_page-i)*4096
4762                                 - page_table[i].first_object_offset)/4;
4763                     
4764                     {
4765                         new_areas_ignore_page = last_page;
4766                         
4767                         scavenge(page_address(i) +
4768                                  page_table[i].first_object_offset,
4769                                  size);
4770
4771                     }
4772                 }
4773             }
4774
4775             i = last_page;
4776         }
4777     }
4778     FSHOW((stderr,
4779            "/done with one full scan of newspace generation %d\n",
4780            generation));
4781 }
4782
4783 /* Do a complete scavenge of the newspace generation. */
4784 static void
4785 scavenge_newspace_generation(int generation)
4786 {
4787     int i;
4788
4789     /* the new_areas array currently being written to by gc_alloc */
4790     struct new_area (*current_new_areas)[] = &new_areas_1;
4791     int current_new_areas_index;
4792
4793     /* the new_areas created but the previous scavenge cycle */
4794     struct new_area (*previous_new_areas)[] = NULL;
4795     int previous_new_areas_index;
4796
4797     /* Flush the current regions updating the tables. */
4798     gc_alloc_update_page_tables(0, &boxed_region);
4799     gc_alloc_update_page_tables(1, &unboxed_region);
4800
4801     /* Turn on the recording of new areas by gc_alloc. */
4802     new_areas = current_new_areas;
4803     new_areas_index = 0;
4804
4805     /* Don't need to record new areas that get scavenged anyway during
4806      * scavenge_newspace_generation_one_scan. */
4807     record_new_objects = 1;
4808
4809     /* Start with a full scavenge. */
4810     scavenge_newspace_generation_one_scan(generation);
4811
4812     /* Record all new areas now. */
4813     record_new_objects = 2;
4814
4815     /* Flush the current regions updating the tables. */
4816     gc_alloc_update_page_tables(0, &boxed_region);
4817     gc_alloc_update_page_tables(1, &unboxed_region);
4818
4819     /* Grab new_areas_index. */
4820     current_new_areas_index = new_areas_index;
4821
4822     /*FSHOW((stderr,
4823              "The first scan is finished; current_new_areas_index=%d.\n",
4824              current_new_areas_index));*/
4825
4826     while (current_new_areas_index > 0) {
4827         /* Move the current to the previous new areas */
4828         previous_new_areas = current_new_areas;
4829         previous_new_areas_index = current_new_areas_index;
4830
4831         /* Scavenge all the areas in previous new areas. Any new areas
4832          * allocated are saved in current_new_areas. */
4833
4834         /* Allocate an array for current_new_areas; alternating between
4835          * new_areas_1 and 2 */
4836         if (previous_new_areas == &new_areas_1)
4837             current_new_areas = &new_areas_2;
4838         else
4839             current_new_areas = &new_areas_1;
4840
4841         /* Set up for gc_alloc. */
4842         new_areas = current_new_areas;
4843         new_areas_index = 0;
4844
4845         /* Check whether previous_new_areas had overflowed. */
4846         if (previous_new_areas_index >= NUM_NEW_AREAS) {
4847
4848             /* New areas of objects allocated have been lost so need to do a
4849              * full scan to be sure! If this becomes a problem try
4850              * increasing NUM_NEW_AREAS. */
4851             if (gencgc_verbose)
4852                 SHOW("new_areas overflow, doing full scavenge");
4853
4854             /* Don't need to record new areas that get scavenge anyway
4855              * during scavenge_newspace_generation_one_scan. */
4856             record_new_objects = 1;
4857
4858             scavenge_newspace_generation_one_scan(generation);
4859
4860             /* Record all new areas now. */
4861             record_new_objects = 2;
4862
4863             /* Flush the current regions updating the tables. */
4864             gc_alloc_update_page_tables(0, &boxed_region);
4865             gc_alloc_update_page_tables(1, &unboxed_region);
4866
4867         } else {
4868
4869             /* Work through previous_new_areas. */
4870             for (i = 0; i < previous_new_areas_index; i++) {
4871                 /* FIXME: All these bare *4 and /4 should be something
4872                  * like BYTES_PER_WORD or WBYTES. */
4873                 int page = (*previous_new_areas)[i].page;
4874                 int offset = (*previous_new_areas)[i].offset;
4875                 int size = (*previous_new_areas)[i].size / 4;
4876                 gc_assert((*previous_new_areas)[i].size % 4 == 0);
4877
4878                 scavenge(page_address(page)+offset, size);
4879             }
4880
4881             /* Flush the current regions updating the tables. */
4882             gc_alloc_update_page_tables(0, &boxed_region);
4883             gc_alloc_update_page_tables(1, &unboxed_region);
4884         }
4885
4886         current_new_areas_index = new_areas_index;
4887
4888         /*FSHOW((stderr,
4889                  "The re-scan has finished; current_new_areas_index=%d.\n",
4890                  current_new_areas_index));*/
4891     }
4892
4893     /* Turn off recording of areas allocated by gc_alloc. */
4894     record_new_objects = 0;
4895
4896 #if SC_NS_GEN_CK
4897     /* Check that none of the write_protected pages in this generation
4898      * have been written to. */
4899     for (i = 0; i < NUM_PAGES; i++) {
4900         if ((page_table[i].allocation != FREE_PAGE)
4901             && (page_table[i].bytes_used != 0)
4902             && (page_table[i].gen == generation)
4903             && (page_table[i].write_protected_cleared != 0)
4904             && (page_table[i].dont_move == 0)) {
4905             lose("write protected page %d written to in scavenge_newspace_generation\ngeneration=%d dont_move=%d",
4906                  i, generation, page_table[i].dont_move);
4907         }
4908     }
4909 #endif
4910 }
4911 \f
4912 /* Un-write-protect all the pages in from_space. This is done at the
4913  * start of a GC else there may be many page faults while scavenging
4914  * the newspace (I've seen drive the system time to 99%). These pages
4915  * would need to be unprotected anyway before unmapping in
4916  * free_oldspace; not sure what effect this has on paging.. */
4917 static void
4918 unprotect_oldspace(void)
4919 {
4920     int i;
4921
4922     for (i = 0; i < last_free_page; i++) {
4923         if ((page_table[i].allocated != FREE_PAGE)
4924             && (page_table[i].bytes_used != 0)
4925             && (page_table[i].gen == from_space)) {
4926             void *page_start;
4927
4928             page_start = (void *)page_address(i);
4929
4930             /* Remove any write-protection. We should be able to rely
4931              * on the write-protect flag to avoid redundant calls. */
4932             if (page_table[i].write_protected) {
4933                 os_protect(page_start, 4096, OS_VM_PROT_ALL);
4934                 page_table[i].write_protected = 0;
4935             }
4936         }
4937     }
4938 }
4939
4940 /* Work through all the pages and free any in from_space. This
4941  * assumes that all objects have been copied or promoted to an older
4942  * generation. Bytes_allocated and the generation bytes_allocated
4943  * counter are updated. The number of bytes freed is returned. */
4944 extern void i586_bzero(void *addr, int nbytes);
4945 static int
4946 free_oldspace(void)
4947 {
4948     int bytes_freed = 0;
4949     int first_page, last_page;
4950
4951     first_page = 0;
4952
4953     do {
4954         /* Find a first page for the next region of pages. */
4955         while ((first_page < last_free_page)
4956                && ((page_table[first_page].allocated == FREE_PAGE)
4957                    || (page_table[first_page].bytes_used == 0)
4958                    || (page_table[first_page].gen != from_space)))
4959             first_page++;
4960
4961         if (first_page >= last_free_page)
4962             break;
4963
4964         /* Find the last page of this region. */
4965         last_page = first_page;
4966
4967         do {
4968             /* Free the page. */
4969             bytes_freed += page_table[last_page].bytes_used;
4970             generations[page_table[last_page].gen].bytes_allocated -=
4971                 page_table[last_page].bytes_used;
4972             page_table[last_page].allocated = FREE_PAGE;
4973             page_table[last_page].bytes_used = 0;
4974
4975             /* Remove any write-protection. We should be able to rely
4976              * on the write-protect flag to avoid redundant calls. */
4977             {
4978                 void  *page_start = (void *)page_address(last_page);
4979         
4980                 if (page_table[last_page].write_protected) {
4981                     os_protect(page_start, 4096, OS_VM_PROT_ALL);
4982                     page_table[last_page].write_protected = 0;
4983                 }
4984             }
4985             last_page++;
4986         }
4987         while ((last_page < last_free_page)
4988                && (page_table[last_page].allocated != FREE_PAGE)
4989                && (page_table[last_page].bytes_used != 0)
4990                && (page_table[last_page].gen == from_space));
4991
4992         /* Zero pages from first_page to (last_page-1).
4993          *
4994          * FIXME: Why not use os_zero(..) function instead of
4995          * hand-coding this again? (Check other gencgc_unmap_zero
4996          * stuff too. */
4997         if (gencgc_unmap_zero) {
4998             void *page_start, *addr;
4999
5000             page_start = (void *)page_address(first_page);
5001
5002             os_invalidate(page_start, 4096*(last_page-first_page));
5003             addr = os_validate(page_start, 4096*(last_page-first_page));
5004             if (addr == NULL || addr != page_start) {
5005                 /* Is this an error condition? I couldn't really tell from
5006                  * the old CMU CL code, which fprintf'ed a message with
5007                  * an exclamation point at the end. But I've never seen the
5008                  * message, so it must at least be unusual..
5009                  *
5010                  * (The same condition is also tested for in gc_free_heap.)
5011                  *
5012                  * -- WHN 19991129 */
5013                 lose("i586_bzero: page moved, 0x%08x ==> 0x%08x",
5014                      page_start,
5015                      addr);
5016             }
5017         } else {
5018             int *page_start;
5019
5020             page_start = (int *)page_address(first_page);
5021             i586_bzero(page_start, 4096*(last_page-first_page));
5022         }
5023
5024         first_page = last_page;
5025
5026     } while (first_page < last_free_page);
5027
5028     bytes_allocated -= bytes_freed;
5029     return bytes_freed;
5030 }
5031 \f
5032 /* Print some information about a pointer at the given address. */
5033 static void
5034 print_ptr(lispobj *addr)
5035 {
5036     /* If addr is in the dynamic space then out the page information. */
5037     int pi1 = find_page_index((void*)addr);
5038
5039     if (pi1 != -1)
5040         fprintf(stderr,"  %x: page %d  alloc %d  gen %d  bytes_used %d  offset %d  dont_move %d\n",
5041                 (unsigned int) addr,
5042                 pi1,
5043                 page_table[pi1].allocated,
5044                 page_table[pi1].gen,
5045                 page_table[pi1].bytes_used,
5046                 page_table[pi1].first_object_offset,
5047                 page_table[pi1].dont_move);
5048     fprintf(stderr,"  %x %x %x %x (%x) %x %x %x %x\n",
5049             *(addr-4),
5050             *(addr-3),
5051             *(addr-2),
5052             *(addr-1),
5053             *(addr-0),
5054             *(addr+1),
5055             *(addr+2),
5056             *(addr+3),
5057             *(addr+4));
5058 }
5059
5060 extern int undefined_tramp;
5061
5062 static void
5063 verify_space(lispobj *start, size_t words)
5064 {
5065     int is_in_dynamic_space = (find_page_index((void*)start) != -1);
5066     int is_in_readonly_space =
5067         (READ_ONLY_SPACE_START <= (unsigned)start &&
5068          (unsigned)start < SymbolValue(READ_ONLY_SPACE_FREE_POINTER));
5069
5070     while (words > 0) {
5071         size_t count = 1;
5072         lispobj thing = *(lispobj*)start;
5073
5074         if (Pointerp(thing)) {
5075             int page_index = find_page_index((void*)thing);
5076             int to_readonly_space =
5077                 (READ_ONLY_SPACE_START <= thing &&
5078                  thing < SymbolValue(READ_ONLY_SPACE_FREE_POINTER));
5079             int to_static_space =
5080                 (STATIC_SPACE_START <= thing &&
5081                  thing < SymbolValue(STATIC_SPACE_FREE_POINTER));
5082
5083             /* Does it point to the dynamic space? */
5084             if (page_index != -1) {
5085                 /* If it's within the dynamic space it should point to a used
5086                  * page. XX Could check the offset too. */
5087                 if ((page_table[page_index].allocated != FREE_PAGE)
5088                     && (page_table[page_index].bytes_used == 0))
5089                     lose ("Ptr %x @ %x sees free page.", thing, start);
5090                 /* Check that it doesn't point to a forwarding pointer! */
5091                 if (*((lispobj *)PTR(thing)) == 0x01) {
5092                     lose("Ptr %x @ %x sees forwarding ptr.", thing, start);
5093                 }
5094                 /* Check that its not in the RO space as it would then be a
5095                  * pointer from the RO to the dynamic space. */
5096                 if (is_in_readonly_space) {
5097                     lose("ptr to dynamic space %x from RO space %x",
5098                          thing, start);
5099                 }
5100                 /* Does it point to a plausible object? This check slows
5101                  * it down a lot (so it's commented out).
5102                  *
5103                  * FIXME: Add a variable to enable this dynamically. */
5104                 /* if (!valid_dynamic_space_pointer((lispobj *)thing)) {
5105                  *     lose("ptr %x to invalid object %x", thing, start); */
5106             } else {
5107                 /* Verify that it points to another valid space. */
5108                 if (!to_readonly_space && !to_static_space
5109                     && (thing != (unsigned)&undefined_tramp)) {
5110                     lose("Ptr %x @ %x sees junk.", thing, start);
5111                 }
5112             }
5113         } else {
5114             if (thing & 0x3) { /* Skip fixnums. FIXME: There should be an
5115                                 * is_fixnum for this. */
5116
5117                 switch(TypeOf(*start)) {
5118
5119                     /* boxed objects */
5120                 case type_SimpleVector:
5121                 case type_Ratio:
5122                 case type_Complex:
5123                 case type_SimpleArray:
5124                 case type_ComplexString:
5125                 case type_ComplexBitVector:
5126                 case type_ComplexVector:
5127                 case type_ComplexArray:
5128                 case type_ClosureHeader:
5129                 case type_FuncallableInstanceHeader:
5130                 case type_ByteCodeFunction:
5131                 case type_ByteCodeClosure:
5132                 case type_ValueCellHeader:
5133                 case type_SymbolHeader:
5134                 case type_BaseChar:
5135                 case type_UnboundMarker:
5136                 case type_InstanceHeader:
5137                 case type_Fdefn:
5138                     count = 1;
5139                     break;
5140
5141                 case type_CodeHeader:
5142                     {
5143                         lispobj object = *start;
5144                         struct code *code;
5145                         int nheader_words, ncode_words, nwords;
5146                         lispobj fheaderl;
5147                         struct function *fheaderp;
5148
5149                         code = (struct code *) start;
5150
5151                         /* Check that it's not in the dynamic space.
5152                          * FIXME: Isn't is supposed to be OK for code
5153                          * objects to be in the dynamic space these days? */
5154                         if (is_in_dynamic_space
5155                             /* It's ok if it's byte compiled code. The trace
5156                              * table offset will be a fixnum if it's x86
5157                              * compiled code - check. */
5158                             && !(code->trace_table_offset & 0x3)
5159                             /* Only when enabled */
5160                             && verify_dynamic_code_check) {
5161                             FSHOW((stderr,
5162                                    "/code object at %x in the dynamic space\n",
5163                                    start));
5164                         }
5165
5166                         ncode_words = fixnum_value(code->code_size);
5167                         nheader_words = HeaderValue(object);
5168                         nwords = ncode_words + nheader_words;
5169                         nwords = CEILING(nwords, 2);
5170                         /* Scavenge the boxed section of the code data block */
5171                         verify_space(start + 1, nheader_words - 1);
5172
5173                         /* Scavenge the boxed section of each function object in
5174                          * the code data block. */
5175                         fheaderl = code->entry_points;
5176                         while (fheaderl != NIL) {
5177                             fheaderp = (struct function *) PTR(fheaderl);
5178                             gc_assert(TypeOf(fheaderp->header) == type_FunctionHeader);
5179                             verify_space(&fheaderp->name, 1);
5180                             verify_space(&fheaderp->arglist, 1);
5181                             verify_space(&fheaderp->type, 1);
5182                             fheaderl = fheaderp->next;
5183                         }
5184                         count = nwords;
5185                         break;
5186                     }
5187         
5188                     /* unboxed objects */
5189                 case type_Bignum:
5190                 case type_SingleFloat:
5191                 case type_DoubleFloat:
5192 #ifdef type_ComplexLongFloat
5193                 case type_LongFloat:
5194 #endif
5195 #ifdef type_ComplexSingleFloat
5196                 case type_ComplexSingleFloat:
5197 #endif
5198 #ifdef type_ComplexDoubleFloat
5199                 case type_ComplexDoubleFloat:
5200 #endif
5201 #ifdef type_ComplexLongFloat
5202                 case type_ComplexLongFloat:
5203 #endif
5204                 case type_SimpleString:
5205                 case type_SimpleBitVector:
5206                 case type_SimpleArrayUnsignedByte2:
5207                 case type_SimpleArrayUnsignedByte4:
5208                 case type_SimpleArrayUnsignedByte8:
5209                 case type_SimpleArrayUnsignedByte16:
5210                 case type_SimpleArrayUnsignedByte32:
5211 #ifdef type_SimpleArraySignedByte8
5212                 case type_SimpleArraySignedByte8:
5213 #endif
5214 #ifdef type_SimpleArraySignedByte16
5215                 case type_SimpleArraySignedByte16:
5216 #endif
5217 #ifdef type_SimpleArraySignedByte30
5218                 case type_SimpleArraySignedByte30:
5219 #endif
5220 #ifdef type_SimpleArraySignedByte32
5221                 case type_SimpleArraySignedByte32:
5222 #endif
5223                 case type_SimpleArraySingleFloat:
5224                 case type_SimpleArrayDoubleFloat:
5225 #ifdef type_SimpleArrayComplexLongFloat
5226                 case type_SimpleArrayLongFloat:
5227 #endif
5228 #ifdef type_SimpleArrayComplexSingleFloat
5229                 case type_SimpleArrayComplexSingleFloat:
5230 #endif
5231 #ifdef type_SimpleArrayComplexDoubleFloat
5232                 case type_SimpleArrayComplexDoubleFloat:
5233 #endif
5234 #ifdef type_SimpleArrayComplexLongFloat
5235                 case type_SimpleArrayComplexLongFloat:
5236 #endif
5237                 case type_Sap:
5238                 case type_WeakPointer:
5239                     count = (sizetab[TypeOf(*start)])(start);
5240                     break;
5241
5242                 default:
5243                     gc_abort();
5244                 }
5245             }
5246         }
5247         start += count;
5248         words -= count;
5249     }
5250 }
5251
5252 static void
5253 verify_gc(void)
5254 {
5255     /* FIXME: It would be nice to make names consistent so that
5256      * foo_size meant size *in* *bytes* instead of size in some
5257      * arbitrary units. (Yes, this caused a bug, how did you guess?:-)
5258      * Some counts of lispobjs are called foo_count; it might be good
5259      * to grep for all foo_size and rename the appropriate ones to
5260      * foo_count. */
5261     int read_only_space_size =
5262         (lispobj*)SymbolValue(READ_ONLY_SPACE_FREE_POINTER)
5263         - (lispobj*)READ_ONLY_SPACE_START;
5264     int static_space_size =
5265         (lispobj*)SymbolValue(STATIC_SPACE_FREE_POINTER)
5266         - (lispobj*)STATIC_SPACE_START;
5267     int binding_stack_size =
5268         (lispobj*)SymbolValue(BINDING_STACK_POINTER)
5269         - (lispobj*)BINDING_STACK_START;
5270
5271     verify_space((lispobj*)READ_ONLY_SPACE_START, read_only_space_size);
5272     verify_space((lispobj*)STATIC_SPACE_START   , static_space_size);
5273     verify_space((lispobj*)BINDING_STACK_START  , binding_stack_size);
5274 }
5275
5276 static void
5277 verify_generation(int  generation)
5278 {
5279     int i;
5280
5281     for (i = 0; i < last_free_page; i++) {
5282         if ((page_table[i].allocated != FREE_PAGE)
5283             && (page_table[i].bytes_used != 0)
5284             && (page_table[i].gen == generation)) {
5285             int last_page;
5286             int region_allocation = page_table[i].allocated;
5287
5288             /* This should be the start of a contiguous block */
5289             gc_assert(page_table[i].first_object_offset == 0);
5290
5291             /* Need to find the full extent of this contiguous block in case
5292                objects span pages. */
5293
5294             /* Now work forward until the end of this contiguous area is
5295                found. */
5296             for (last_page = i; ;last_page++)
5297                 /* Check whether this is the last page in this contiguous
5298                  * block. */
5299                 if ((page_table[last_page].bytes_used < 4096)
5300                     /* Or it is 4096 and is the last in the block */
5301                     || (page_table[last_page+1].allocated != region_allocation)
5302                     || (page_table[last_page+1].bytes_used == 0)
5303                     || (page_table[last_page+1].gen != generation)
5304                     || (page_table[last_page+1].first_object_offset == 0))
5305                     break;
5306
5307             verify_space(page_address(i), (page_table[last_page].bytes_used
5308                                            + (last_page-i)*4096)/4);
5309             i = last_page;
5310         }
5311     }
5312 }
5313
5314 /* Check the all the free space is zero filled. */
5315 static void
5316 verify_zero_fill(void)
5317 {
5318     int page;
5319
5320     for (page = 0; page < last_free_page; page++) {
5321         if (page_table[page].allocated == FREE_PAGE) {
5322             /* The whole page should be zero filled. */
5323             int *start_addr = (int *)page_address(page);
5324             int size = 1024;
5325             int i;
5326             for (i = 0; i < size; i++) {
5327                 if (start_addr[i] != 0) {
5328                     lose("free page not zero at %x", start_addr + i);
5329                 }
5330             }
5331         } else {
5332             int free_bytes = 4096 - page_table[page].bytes_used;
5333             if (free_bytes > 0) {
5334                 int *start_addr = (int *)((unsigned)page_address(page)
5335                                           + page_table[page].bytes_used);
5336                 int size = free_bytes / 4;
5337                 int i;
5338                 for (i = 0; i < size; i++) {
5339                     if (start_addr[i] != 0) {
5340                         lose("free region not zero at %x", start_addr + i);
5341                     }
5342                 }
5343             }
5344         }
5345     }
5346 }
5347
5348 /* External entry point for verify_zero_fill */
5349 void
5350 gencgc_verify_zero_fill(void)
5351 {
5352     /* Flush the alloc regions updating the tables. */
5353     boxed_region.free_pointer = current_region_free_pointer;
5354     gc_alloc_update_page_tables(0, &boxed_region);
5355     gc_alloc_update_page_tables(1, &unboxed_region);
5356     SHOW("verifying zero fill");
5357     verify_zero_fill();
5358     current_region_free_pointer = boxed_region.free_pointer;
5359     current_region_end_addr = boxed_region.end_addr;
5360 }
5361
5362 static void
5363 verify_dynamic_space(void)
5364 {
5365     int i;
5366
5367     for (i = 0; i < NUM_GENERATIONS; i++)
5368         verify_generation(i);
5369
5370     if (gencgc_enable_verify_zero_fill)
5371         verify_zero_fill();
5372 }
5373 \f
5374 /* Write-protect all the dynamic boxed pages in the given generation. */
5375 static void
5376 write_protect_generation_pages(int generation)
5377 {
5378     int i;
5379
5380     gc_assert(generation < NUM_GENERATIONS);
5381
5382     for (i = 0; i < last_free_page; i++)
5383         if ((page_table[i].allocated == BOXED_PAGE)
5384             && (page_table[i].bytes_used != 0)
5385             && (page_table[i].gen == generation))  {
5386             void *page_start;
5387
5388             page_start = (void *)page_address(i);
5389
5390             os_protect(page_start,
5391                        4096,
5392                        OS_VM_PROT_READ | OS_VM_PROT_EXECUTE);
5393
5394             /* Note the page as protected in the page tables. */
5395             page_table[i].write_protected = 1;
5396         }
5397
5398     if (gencgc_verbose > 1) {
5399         FSHOW((stderr,
5400                "/write protected %d of %d pages in generation %d\n",
5401                count_write_protect_generation_pages(generation),
5402                count_generation_pages(generation),
5403                generation));
5404     }
5405 }
5406
5407 /* Garbage collect a generation. If raise is 0 the remains of the
5408  * generation are not raised to the next generation. */
5409 static void
5410 garbage_collect_generation(int generation, int raise)
5411 {
5412     unsigned long bytes_freed;
5413     unsigned long i;
5414     unsigned long read_only_space_size, static_space_size;
5415
5416     gc_assert(generation <= (NUM_GENERATIONS-1));
5417
5418     /* The oldest generation can't be raised. */
5419     gc_assert((generation != (NUM_GENERATIONS-1)) || (raise == 0));
5420
5421     /* Initialize the weak pointer list. */
5422     weak_pointers = NULL;
5423
5424     /* When a generation is not being raised it is transported to a
5425      * temporary generation (NUM_GENERATIONS), and lowered when
5426      * done. Set up this new generation. There should be no pages
5427      * allocated to it yet. */
5428     if (!raise)
5429         gc_assert(generations[NUM_GENERATIONS].bytes_allocated == 0);
5430
5431     /* Set the global src and dest. generations */
5432     from_space = generation;
5433     if (raise)
5434         new_space = generation+1;
5435     else
5436         new_space = NUM_GENERATIONS;
5437
5438     /* Change to a new space for allocation, resetting the alloc_start_page */
5439     gc_alloc_generation = new_space;
5440     generations[new_space].alloc_start_page = 0;
5441     generations[new_space].alloc_unboxed_start_page = 0;
5442     generations[new_space].alloc_large_start_page = 0;
5443     generations[new_space].alloc_large_unboxed_start_page = 0;
5444
5445     /* Before any pointers are preserved, the dont_move flags on the
5446      * pages need to be cleared. */
5447     for (i = 0; i < last_free_page; i++)
5448         page_table[i].dont_move = 0;
5449
5450     /* Un-write-protect the old-space pages. This is essential for the
5451      * promoted pages as they may contain pointers into the old-space
5452      * which need to be scavenged. It also helps avoid unnecessary page
5453      * faults as forwarding pointer are written into them. They need to
5454      * be un-protected anyway before unmapping later. */
5455     unprotect_oldspace();
5456
5457     /* Scavenge the stack's conservative roots. */
5458     {
5459         lispobj **ptr;
5460         for (ptr = (lispobj **)CONTROL_STACK_END - 1;
5461              ptr > (lispobj **)&raise;
5462              ptr--) {
5463             preserve_pointer(*ptr);
5464         }
5465     }
5466 #ifdef CONTROL_STACKS
5467     scavenge_thread_stacks();
5468 #endif
5469
5470     if (gencgc_verbose > 1) {
5471         int num_dont_move_pages = count_dont_move_pages();
5472         FSHOW((stderr,
5473                "/non-movable pages due to conservative pointers = %d (%d bytes)\n",
5474                num_dont_move_pages,
5475                /* FIXME: 4096 should be symbolic constant here and
5476                 * prob'ly elsewhere too. */
5477                num_dont_move_pages * 4096));
5478     }
5479
5480     /* Scavenge all the rest of the roots. */
5481
5482     /* Scavenge the Lisp functions of the interrupt handlers, taking
5483      * care to avoid SIG_DFL, SIG_IGN. */
5484     for (i = 0; i < NSIG; i++) {
5485         union interrupt_handler handler = interrupt_handlers[i];
5486         if (!ARE_SAME_HANDLER(handler.c, SIG_IGN) &&
5487             !ARE_SAME_HANDLER(handler.c, SIG_DFL)) {
5488             scavenge((lispobj *)(interrupt_handlers + i), 1);
5489         }
5490     }
5491
5492     /* Scavenge the binding stack. */
5493     scavenge( (lispobj *) BINDING_STACK_START,
5494              (lispobj *)SymbolValue(BINDING_STACK_POINTER) -
5495              (lispobj *)BINDING_STACK_START);
5496
5497     /* The original CMU CL code had scavenge-read-only-space code
5498      * controlled by the Lisp-level variable
5499      * *SCAVENGE-READ-ONLY-SPACE*. It was disabled by default, and it
5500      * wasn't documented under what circumstances it was useful or
5501      * safe to turn it on, so it's been turned off in SBCL. If you
5502      * want/need this functionality, and can test and document it,
5503      * please submit a patch. */
5504 #if 0
5505     if (SymbolValue(SCAVENGE_READ_ONLY_SPACE) != NIL) {
5506         read_only_space_size =
5507             (lispobj*)SymbolValue(READ_ONLY_SPACE_FREE_POINTER) -
5508             (lispobj*)READ_ONLY_SPACE_START;
5509         FSHOW((stderr,
5510                "/scavenge read only space: %d bytes\n",
5511                read_only_space_size * sizeof(lispobj)));
5512         scavenge( (lispobj *) READ_ONLY_SPACE_START, read_only_space_size);
5513     }
5514 #endif
5515
5516     static_space_size =
5517         (lispobj *)SymbolValue(STATIC_SPACE_FREE_POINTER) -
5518         (lispobj *)STATIC_SPACE_START;
5519     if (gencgc_verbose > 1)
5520         FSHOW((stderr,
5521                "/scavenge static space: %d bytes\n",
5522                static_space_size * sizeof(lispobj)));
5523     scavenge( (lispobj *) STATIC_SPACE_START, static_space_size);
5524
5525     /* All generations but the generation being GCed need to be
5526      * scavenged. The new_space generation needs special handling as
5527      * objects may be moved in - it is handled separately below. */
5528     for (i = 0; i < NUM_GENERATIONS; i++)
5529         if ((i != generation) && (i != new_space))
5530             scavenge_generation(i);
5531
5532     /* Finally scavenge the new_space generation. Keep going until no
5533      * more objects are moved into the new generation */
5534     scavenge_newspace_generation(new_space);
5535
5536 #define RESCAN_CHECK 0
5537 #if RESCAN_CHECK
5538     /* As a check re-scavenge the newspace once; no new objects should
5539      * be found. */
5540     {
5541         int old_bytes_allocated = bytes_allocated;
5542         int bytes_allocated;
5543
5544         /* Start with a full scavenge. */
5545         scavenge_newspace_generation_one_scan(new_space);
5546
5547         /* Flush the current regions, updating the tables. */
5548         gc_alloc_update_page_tables(0, &boxed_region);
5549         gc_alloc_update_page_tables(1, &unboxed_region);
5550
5551         bytes_allocated = bytes_allocated - old_bytes_allocated;
5552
5553         if (bytes_allocated != 0) {
5554             lose("Rescan of new_space allocated %d more bytes.",
5555                  bytes_allocated);
5556         }
5557     }
5558 #endif
5559
5560     scan_weak_pointers();
5561
5562     /* Flush the current regions, updating the tables. */
5563     gc_alloc_update_page_tables(0, &boxed_region);
5564     gc_alloc_update_page_tables(1, &unboxed_region);
5565
5566     /* Free the pages in oldspace, but not those marked dont_move. */
5567     bytes_freed = free_oldspace();
5568
5569     /* If the GC is not raising the age then lower the generation back
5570      * to its normal generation number */
5571     if (!raise) {
5572         for (i = 0; i < last_free_page; i++)
5573             if ((page_table[i].bytes_used != 0)
5574                 && (page_table[i].gen == NUM_GENERATIONS))
5575                 page_table[i].gen = generation;
5576         gc_assert(generations[generation].bytes_allocated == 0);
5577         generations[generation].bytes_allocated =
5578             generations[NUM_GENERATIONS].bytes_allocated;
5579         generations[NUM_GENERATIONS].bytes_allocated = 0;
5580     }
5581
5582     /* Reset the alloc_start_page for generation. */
5583     generations[generation].alloc_start_page = 0;
5584     generations[generation].alloc_unboxed_start_page = 0;
5585     generations[generation].alloc_large_start_page = 0;
5586     generations[generation].alloc_large_unboxed_start_page = 0;
5587
5588     if (generation >= verify_gens) {
5589         if (gencgc_verbose)
5590             SHOW("verifying");
5591         verify_gc();
5592         verify_dynamic_space();
5593     }
5594
5595     /* Set the new gc trigger for the GCed generation. */
5596     generations[generation].gc_trigger =
5597         generations[generation].bytes_allocated
5598         + generations[generation].bytes_consed_between_gc;
5599
5600     if (raise)
5601         generations[generation].num_gc = 0;
5602     else
5603         ++generations[generation].num_gc;
5604 }
5605
5606 /* Update last_free_page then ALLOCATION_POINTER */
5607 int
5608 update_x86_dynamic_space_free_pointer(void)
5609 {
5610     int last_page = -1;
5611     int i;
5612
5613     for (i = 0; i < NUM_PAGES; i++)
5614         if ((page_table[i].allocated != FREE_PAGE)
5615             && (page_table[i].bytes_used != 0))
5616             last_page = i;
5617
5618     last_free_page = last_page+1;
5619
5620     SetSymbolValue(ALLOCATION_POINTER,
5621                    (lispobj)(((char *)heap_base) + last_free_page*4096));
5622     return 0; /* dummy value: return something ... */
5623 }
5624
5625 /* GC all generations below last_gen, raising their objects to the
5626  * next generation until all generations below last_gen are empty.
5627  * Then if last_gen is due for a GC then GC it. In the special case
5628  * that last_gen==NUM_GENERATIONS, the last generation is always
5629  * GC'ed. The valid range for last_gen is: 0,1,...,NUM_GENERATIONS.
5630  *
5631  * The oldest generation to be GCed will always be
5632  * gencgc_oldest_gen_to_gc, partly ignoring last_gen if necessary. */
5633 void
5634 collect_garbage(unsigned last_gen)
5635 {
5636     int gen = 0;
5637     int raise;
5638     int gen_to_wp;
5639     int i;
5640
5641     boxed_region.free_pointer = current_region_free_pointer;
5642
5643     FSHOW((stderr, "/entering collect_garbage(%d)\n", last_gen));
5644
5645     if (last_gen > NUM_GENERATIONS) {
5646         FSHOW((stderr,
5647                "/collect_garbage: last_gen = %d, doing a level 0 GC\n",
5648                last_gen));
5649         last_gen = 0;
5650     }
5651
5652     /* Flush the alloc regions updating the tables. */
5653     gc_alloc_update_page_tables(0, &boxed_region);
5654     gc_alloc_update_page_tables(1, &unboxed_region);
5655
5656     /* Verify the new objects created by Lisp code. */
5657     if (pre_verify_gen_0) {
5658         SHOW((stderr, "pre-checking generation 0\n"));
5659         verify_generation(0);
5660     }
5661
5662     if (gencgc_verbose > 1)
5663         print_generation_stats(0);
5664
5665     do {
5666         /* Collect the generation. */
5667
5668         if (gen >= gencgc_oldest_gen_to_gc) {
5669             /* Never raise the oldest generation. */
5670             raise = 0;
5671         } else {
5672             raise =
5673                 (gen < last_gen)
5674                 || (generations[gen].num_gc >= generations[gen].trigger_age);
5675         }
5676
5677         if (gencgc_verbose > 1) {
5678             FSHOW((stderr,
5679                    "starting GC of generation %d with raise=%d alloc=%d trig=%d GCs=%d\n",
5680                    gen,
5681                    raise,
5682                    generations[gen].bytes_allocated,
5683                    generations[gen].gc_trigger,
5684                    generations[gen].num_gc));
5685         }
5686
5687         /* If an older generation is being filled, then update its
5688          * memory age. */
5689         if (raise == 1) {
5690             generations[gen+1].cum_sum_bytes_allocated +=
5691                 generations[gen+1].bytes_allocated;
5692         }
5693
5694         garbage_collect_generation(gen, raise);
5695
5696         /* Reset the memory age cum_sum. */
5697         generations[gen].cum_sum_bytes_allocated = 0;
5698
5699         if (gencgc_verbose > 1) {
5700             FSHOW((stderr, "GC of generation %d finished:\n", gen));
5701             print_generation_stats(0);
5702         }
5703
5704         gen++;
5705     } while ((gen <= gencgc_oldest_gen_to_gc)
5706              && ((gen < last_gen)
5707                  || ((gen <= gencgc_oldest_gen_to_gc)
5708                      && raise
5709                      && (generations[gen].bytes_allocated
5710                          > generations[gen].gc_trigger)
5711                      && (gen_av_mem_age(gen)
5712                          > generations[gen].min_av_mem_age))));
5713
5714     /* Now if gen-1 was raised all generations before gen are empty.
5715      * If it wasn't raised then all generations before gen-1 are empty.
5716      *
5717      * Now objects within this gen's pages cannot point to younger
5718      * generations unless they are written to. This can be exploited
5719      * by write-protecting the pages of gen; then when younger
5720      * generations are GCed only the pages which have been written
5721      * need scanning. */
5722     if (raise)
5723         gen_to_wp = gen;
5724     else
5725         gen_to_wp = gen - 1;
5726
5727     /* There's not much point in WPing pages in generation 0 as it is
5728      * never scavenged (except promoted pages). */
5729     if ((gen_to_wp > 0) && enable_page_protection) {
5730         /* Check that they are all empty. */
5731         for (i = 0; i < gen_to_wp; i++) {
5732             if (generations[i].bytes_allocated)
5733                 lose("trying to write-protect gen. %d when gen. %d nonempty",
5734                      gen_to_wp, i);
5735         }
5736         write_protect_generation_pages(gen_to_wp);
5737     }
5738
5739     /* Set gc_alloc back to generation 0. The current regions should
5740      * be flushed after the above GCs */
5741     gc_assert((boxed_region.free_pointer - boxed_region.start_addr) == 0);
5742     gc_alloc_generation = 0;
5743
5744     update_x86_dynamic_space_free_pointer();
5745
5746     /* This is now done by Lisp SCRUB-CONTROL-STACK in Lisp SUB-GC, so we
5747      * needn't do it here: */
5748     /*  zero_stack();*/
5749
5750     current_region_free_pointer = boxed_region.free_pointer;
5751     current_region_end_addr = boxed_region.end_addr;
5752
5753     SHOW("returning from collect_garbage");
5754 }
5755
5756 /* This is called by Lisp PURIFY when it is finished. All live objects
5757  * will have been moved to the RO and Static heaps. The dynamic space
5758  * will need a full re-initialization. We don't bother having Lisp
5759  * PURIFY flush the current gc_alloc region, as the page_tables are
5760  * re-initialized, and every page is zeroed to be sure. */
5761 void
5762 gc_free_heap(void)
5763 {
5764     int page;
5765
5766     if (gencgc_verbose > 1)
5767         SHOW("entering gc_free_heap");
5768
5769     for (page = 0; page < NUM_PAGES; page++) {
5770         /* Skip free pages which should already be zero filled. */
5771         if (page_table[page].allocated != FREE_PAGE) {
5772             void *page_start, *addr;
5773
5774             /* Mark the page free. The other slots are assumed invalid
5775              * when it is a FREE_PAGE and bytes_used is 0 and it
5776              * should not be write-protected -- except that the
5777              * generation is used for the current region but it sets
5778              * that up. */
5779             page_table[page].allocated = FREE_PAGE;
5780             page_table[page].bytes_used = 0;
5781
5782             /* Zero the page. */
5783             page_start = (void *)page_address(page);
5784
5785             /* First, remove any write-protection. */
5786             os_protect(page_start, 4096, OS_VM_PROT_ALL);
5787             page_table[page].write_protected = 0;
5788
5789             os_invalidate(page_start,4096);
5790             addr = os_validate(page_start,4096);
5791             if (addr == NULL || addr != page_start) {
5792                 lose("gc_free_heap: page moved, 0x%08x ==> 0x%08x",
5793                      page_start,
5794                      addr);
5795             }
5796         } else if (gencgc_zero_check_during_free_heap) {
5797             /* Double-check that the page is zero filled. */
5798             int *page_start, i;
5799             gc_assert(page_table[page].allocated == FREE_PAGE);
5800             gc_assert(page_table[page].bytes_used == 0);
5801             page_start = (int *)page_address(page);
5802             for (i=0; i<1024; i++) {
5803                 if (page_start[i] != 0) {
5804                     lose("free region not zero at %x", page_start + i);
5805                 }
5806             }
5807         }
5808     }
5809
5810     bytes_allocated = 0;
5811
5812     /* Initialize the generations. */
5813     for (page = 0; page < NUM_GENERATIONS; page++) {
5814         generations[page].alloc_start_page = 0;
5815         generations[page].alloc_unboxed_start_page = 0;
5816         generations[page].alloc_large_start_page = 0;
5817         generations[page].alloc_large_unboxed_start_page = 0;
5818         generations[page].bytes_allocated = 0;
5819         generations[page].gc_trigger = 2000000;
5820         generations[page].num_gc = 0;
5821         generations[page].cum_sum_bytes_allocated = 0;
5822     }
5823
5824     if (gencgc_verbose > 1)
5825         print_generation_stats(0);
5826
5827     /* Initialize gc_alloc */
5828     gc_alloc_generation = 0;
5829     boxed_region.first_page = 0;
5830     boxed_region.last_page = -1;
5831     boxed_region.start_addr = page_address(0);
5832     boxed_region.free_pointer = page_address(0);
5833     boxed_region.end_addr = page_address(0);
5834
5835     unboxed_region.first_page = 0;
5836     unboxed_region.last_page = -1;
5837     unboxed_region.start_addr = page_address(0);
5838     unboxed_region.free_pointer = page_address(0);
5839     unboxed_region.end_addr = page_address(0);
5840
5841 #if 0 /* Lisp PURIFY is currently running on the C stack so don't do this. */
5842     zero_stack();
5843 #endif
5844
5845     last_free_page = 0;
5846     SetSymbolValue(ALLOCATION_POINTER, (lispobj)((char *)heap_base));
5847
5848     current_region_free_pointer = boxed_region.free_pointer;
5849     current_region_end_addr = boxed_region.end_addr;
5850
5851     if (verify_after_free_heap) {
5852         /* Check whether purify has left any bad pointers. */
5853         if (gencgc_verbose)
5854             SHOW("checking after free_heap\n");
5855         verify_gc();
5856     }
5857 }
5858 \f
5859 void
5860 gc_init(void)
5861 {
5862     int i;
5863
5864     gc_init_tables();
5865
5866     heap_base = (void*)DYNAMIC_SPACE_START;
5867
5868     /* Initialize each page structure. */
5869     for (i = 0; i < NUM_PAGES; i++) {
5870         /* Initialize all pages as free. */
5871         page_table[i].allocated = FREE_PAGE;
5872         page_table[i].bytes_used = 0;
5873
5874         /* Pages are not write-protected at startup. */
5875         page_table[i].write_protected = 0;
5876     }
5877
5878     bytes_allocated = 0;
5879
5880     /* Initialize the generations. */
5881     for (i = 0; i < NUM_GENERATIONS; i++) {
5882         generations[i].alloc_start_page = 0;
5883         generations[i].alloc_unboxed_start_page = 0;
5884         generations[i].alloc_large_start_page = 0;
5885         generations[i].alloc_large_unboxed_start_page = 0;
5886         generations[i].bytes_allocated = 0;
5887         generations[i].gc_trigger = 2000000;
5888         generations[i].num_gc = 0;
5889         generations[i].cum_sum_bytes_allocated = 0;
5890         /* the tune-able parameters */
5891         generations[i].bytes_consed_between_gc = 2000000;
5892         generations[i].trigger_age = 1;
5893         generations[i].min_av_mem_age = 0.75;
5894     }
5895
5896     /* Initialize gc_alloc. */
5897     gc_alloc_generation = 0;
5898     boxed_region.first_page = 0;
5899     boxed_region.last_page = -1;
5900     boxed_region.start_addr = page_address(0);
5901     boxed_region.free_pointer = page_address(0);
5902     boxed_region.end_addr = page_address(0);
5903
5904     unboxed_region.first_page = 0;
5905     unboxed_region.last_page = -1;
5906     unboxed_region.start_addr = page_address(0);
5907     unboxed_region.free_pointer = page_address(0);
5908     unboxed_region.end_addr = page_address(0);
5909
5910     last_free_page = 0;
5911
5912     current_region_free_pointer = boxed_region.free_pointer;
5913     current_region_end_addr = boxed_region.end_addr;
5914 }
5915
5916 /*  Pick up the dynamic space from after a core load.
5917  *
5918  *  The ALLOCATION_POINTER points to the end of the dynamic space.
5919  *
5920  *  XX A scan is needed to identify the closest first objects for pages. */
5921 void
5922 gencgc_pickup_dynamic(void)
5923 {
5924     int page = 0;
5925     int addr = DYNAMIC_SPACE_START;
5926     int alloc_ptr = SymbolValue(ALLOCATION_POINTER);
5927
5928     /* Initialize the first region. */
5929     do {
5930         page_table[page].allocated = BOXED_PAGE;
5931         page_table[page].gen = 0;
5932         page_table[page].bytes_used = 4096;
5933         page_table[page].large_object = 0;
5934         page_table[page].first_object_offset =
5935             (void *)DYNAMIC_SPACE_START - page_address(page);
5936         addr += 4096;
5937         page++;
5938     } while (addr < alloc_ptr);
5939
5940     generations[0].bytes_allocated = 4096*page;
5941     bytes_allocated = 4096*page;
5942
5943     current_region_free_pointer = boxed_region.free_pointer;
5944     current_region_end_addr = boxed_region.end_addr;
5945 }
5946 \f
5947 /* a counter for how deep we are in alloc(..) calls */
5948 int alloc_entered = 0;
5949
5950 /* alloc(..) is the external interface for memory allocation. It
5951  * allocates to generation 0. It is not called from within the garbage
5952  * collector as it is only external uses that need the check for heap
5953  * size (GC trigger) and to disable the interrupts (interrupts are
5954  * always disabled during a GC).
5955  *
5956  * The vops that call alloc(..) assume that the returned space is zero-filled.
5957  * (E.g. the most significant word of a 2-word bignum in MOVE-FROM-UNSIGNED.)
5958  *
5959  * The check for a GC trigger is only performed when the current
5960  * region is full, so in most cases it's not needed. Further MAYBE-GC
5961  * is only called once because Lisp will remember "need to collect
5962  * garbage" and get around to it when it can. */
5963 char *
5964 alloc(int nbytes)
5965 {
5966     /* Check for alignment allocation problems. */
5967     gc_assert((((unsigned)current_region_free_pointer & 0x7) == 0)
5968               && ((nbytes & 0x7) == 0));
5969
5970     if (SymbolValue(PSEUDO_ATOMIC_ATOMIC)) {/* if already in a pseudo atomic */
5971         
5972         void *new_free_pointer;
5973
5974     retry1:
5975         if (alloc_entered) {
5976             SHOW("alloc re-entered in already-pseudo-atomic case");
5977         }
5978         ++alloc_entered;
5979
5980         /* Check whether there is room in the current region. */
5981         new_free_pointer = current_region_free_pointer + nbytes;
5982
5983         /* FIXME: Shouldn't we be doing some sort of lock here, to
5984          * keep from getting screwed if an interrupt service routine
5985          * allocates memory between the time we calculate new_free_pointer
5986          * and the time we write it back to current_region_free_pointer?
5987          * Perhaps I just don't understand pseudo-atomics..
5988          *
5989          * Perhaps I don't. It looks as though what happens is if we
5990          * were interrupted any time during the pseudo-atomic
5991          * interval (which includes now) we discard the allocated
5992          * memory and try again. So, at least we don't return
5993          * a memory area that was allocated out from underneath us
5994          * by code in an ISR.
5995          * Still, that doesn't seem to prevent
5996          * current_region_free_pointer from getting corrupted:
5997          *   We read current_region_free_pointer.
5998          *   They read current_region_free_pointer.
5999          *   They write current_region_free_pointer.
6000          *   We write current_region_free_pointer, scribbling over
6001          *     whatever they wrote. */
6002
6003         if (new_free_pointer <= boxed_region.end_addr) {
6004             /* If so then allocate from the current region. */
6005             void  *new_obj = current_region_free_pointer;
6006             current_region_free_pointer = new_free_pointer;
6007             alloc_entered--;
6008             return((void *)new_obj);
6009         }
6010
6011         if (auto_gc_trigger && bytes_allocated > auto_gc_trigger) {
6012             /* Double the trigger. */
6013             auto_gc_trigger *= 2;
6014             alloc_entered--;
6015             /* Exit the pseudo-atomic. */
6016             SetSymbolValue(PSEUDO_ATOMIC_ATOMIC, make_fixnum(0));
6017             if (SymbolValue(PSEUDO_ATOMIC_INTERRUPTED) != 0) {
6018                 /* Handle any interrupts that occurred during
6019                  * gc_alloc(..). */
6020                 do_pending_interrupt();
6021             }
6022             funcall0(SymbolFunction(MAYBE_GC));
6023             /* Re-enter the pseudo-atomic. */
6024             SetSymbolValue(PSEUDO_ATOMIC_INTERRUPTED, make_fixnum(0));
6025             SetSymbolValue(PSEUDO_ATOMIC_ATOMIC, make_fixnum(1));
6026             goto retry1;
6027         }
6028         /* Call gc_alloc. */
6029         boxed_region.free_pointer = current_region_free_pointer;
6030         {
6031             void *new_obj = gc_alloc(nbytes);
6032             current_region_free_pointer = boxed_region.free_pointer;
6033             current_region_end_addr = boxed_region.end_addr;
6034             alloc_entered--;
6035             return (new_obj);
6036         }
6037     } else {
6038         void *result;
6039         void *new_free_pointer;
6040
6041     retry2:
6042         /* At least wrap this allocation in a pseudo atomic to prevent
6043          * gc_alloc from being re-entered. */
6044         SetSymbolValue(PSEUDO_ATOMIC_INTERRUPTED, make_fixnum(0));
6045         SetSymbolValue(PSEUDO_ATOMIC_ATOMIC, make_fixnum(1));
6046
6047         if (alloc_entered)
6048             SHOW("alloc re-entered in not-already-pseudo-atomic case");
6049         ++alloc_entered;
6050
6051         /* Check whether there is room in the current region. */
6052         new_free_pointer = current_region_free_pointer + nbytes;
6053
6054         if (new_free_pointer <= boxed_region.end_addr) {
6055             /* If so then allocate from the current region. */
6056             void *new_obj = current_region_free_pointer;
6057             current_region_free_pointer = new_free_pointer;
6058             alloc_entered--;
6059             SetSymbolValue(PSEUDO_ATOMIC_ATOMIC, make_fixnum(0));
6060             if (SymbolValue(PSEUDO_ATOMIC_INTERRUPTED)) {
6061                 /* Handle any interrupts that occurred during
6062                  * gc_alloc(..). */
6063                 do_pending_interrupt();
6064                 goto retry2;
6065             }
6066
6067             return((void *)new_obj);
6068         }
6069
6070         /* KLUDGE: There's lots of code around here shared with the
6071          * the other branch. Is there some way to factor out the
6072          * duplicate code? -- WHN 19991129 */
6073         if (auto_gc_trigger && bytes_allocated > auto_gc_trigger) {
6074             /* Double the trigger. */
6075             auto_gc_trigger *= 2;
6076             alloc_entered--;
6077             /* Exit the pseudo atomic. */
6078             SetSymbolValue(PSEUDO_ATOMIC_ATOMIC, make_fixnum(0));
6079             if (SymbolValue(PSEUDO_ATOMIC_INTERRUPTED) != 0) {
6080                 /* Handle any interrupts that occurred during
6081                  * gc_alloc(..); */
6082                 do_pending_interrupt();
6083             }
6084             funcall0(SymbolFunction(MAYBE_GC));
6085             goto retry2;
6086         }
6087
6088         /* Else call gc_alloc. */
6089         boxed_region.free_pointer = current_region_free_pointer;
6090         result = gc_alloc(nbytes);
6091         current_region_free_pointer = boxed_region.free_pointer;
6092         current_region_end_addr = boxed_region.end_addr;
6093
6094         alloc_entered--;
6095         SetSymbolValue(PSEUDO_ATOMIC_ATOMIC, make_fixnum(0));
6096         if (SymbolValue(PSEUDO_ATOMIC_INTERRUPTED) != 0) {
6097             /* Handle any interrupts that occurred during
6098              * gc_alloc(..). */
6099             do_pending_interrupt();
6100             goto retry2;
6101         }
6102
6103         return result;
6104     }
6105 }
6106 \f
6107 /*
6108  * noise to manipulate the gc trigger stuff
6109  */
6110
6111 void
6112 set_auto_gc_trigger(os_vm_size_t dynamic_usage)
6113 {
6114     auto_gc_trigger += dynamic_usage;
6115 }
6116
6117 void
6118 clear_auto_gc_trigger(void)
6119 {
6120     auto_gc_trigger = 0;
6121 }
6122 \f
6123 /* Find the code object for the given pc, or return NULL on failure.
6124  *
6125  * FIXME: PC shouldn't be lispobj*, should it? Maybe void*? */
6126 lispobj *
6127 component_ptr_from_pc(lispobj *pc)
6128 {
6129     lispobj *object = NULL;
6130
6131     if ( (object = search_read_only_space(pc)) )
6132         ;
6133     else if ( (object = search_static_space(pc)) )
6134         ;
6135     else
6136         object = search_dynamic_space(pc);
6137
6138     if (object) /* if we found something */
6139         if (TypeOf(*object) == type_CodeHeader) /* if it's a code object */
6140             return(object);
6141
6142     return (NULL);
6143 }
6144 \f
6145 /*
6146  * shared support for the OS-dependent signal handlers which
6147  * catch GENCGC-related write-protect violations
6148  */
6149
6150 void unhandled_sigmemoryfault(void);
6151
6152 /* Depending on which OS we're running under, different signals might
6153  * be raised for a violation of write protection in the heap. This
6154  * function factors out the common generational GC magic which needs
6155  * to invoked in this case, and should be called from whatever signal
6156  * handler is appropriate for the OS we're running under.
6157  *
6158  * Return true if this signal is a normal generational GC thing that
6159  * we were able to handle, or false if it was abnormal and control
6160  * should fall through to the general SIGSEGV/SIGBUS/whatever logic. */
6161 int
6162 gencgc_handle_wp_violation(void* fault_addr)
6163 {
6164     int  page_index = find_page_index(fault_addr);
6165
6166 #if defined QSHOW_SIGNALS
6167     FSHOW((stderr, "heap WP violation? fault_addr=%x, page_index=%d\n",
6168            fault_addr, page_index));
6169 #endif
6170
6171     /* Check whether the fault is within the dynamic space. */
6172     if (page_index == (-1)) {
6173
6174         /* It can be helpful to be able to put a breakpoint on this
6175          * case to help diagnose low-level problems. */
6176         unhandled_sigmemoryfault();
6177
6178         /* not within the dynamic space -- not our responsibility */
6179         return 0;
6180
6181     } else {
6182
6183         /* The only acceptable reason for an signal like this from the
6184          * heap is that the generational GC write-protected the page. */
6185         if (page_table[page_index].write_protected != 1) {
6186             lose("access failure in heap page not marked as write-protected");
6187         }
6188         
6189         /* Unprotect the page. */
6190         os_protect(page_address(page_index), 4096, OS_VM_PROT_ALL);
6191         page_table[page_index].write_protected = 0;
6192         page_table[page_index].write_protected_cleared = 1;
6193
6194         /* Don't worry, we can handle it. */
6195         return 1;
6196     }
6197 }
6198
6199 /* This is to be called when we catch a SIGSEGV/SIGBUS, determine that
6200  * it's not just a case of the program hitting the write barrier, and
6201  * are about to let Lisp deal with it. It's basically just a
6202  * convenient place to set a gdb breakpoint. */
6203 void
6204 unhandled_sigmemoryfault()
6205 {}