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