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