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