0.6.12.21.flaky2.2:
[sbcl.git] / src / runtime / purify.c
1 /*
2  * C-level stuff to implement Lisp-level PURIFY
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 #include <stdio.h>
17 #include <sys/types.h>
18 #include <stdlib.h>
19
20 #include "runtime.h"
21 #include "os.h"
22 #include "sbcl.h"
23 #include "globals.h"
24 #include "validate.h"
25 #include "interrupt.h"
26 #include "purify.h"
27 #include "interr.h"
28 #ifdef GENCGC
29 #include "gencgc.h"
30 #endif
31
32 #define PRINTNOISE
33
34 #if defined(ibmrt) || defined(__i386__)
35 /* again, what's so special about the x86 that this is differently
36  * visible there than on other platforms? -dan 20010125 
37  */
38 static lispobj *dynamic_space_free_pointer;
39 #endif
40
41 #define gc_abort() \
42   lose("GC invariant lost, file \"%s\", line %d", __FILE__, __LINE__)
43
44 #if 1
45 #define gc_assert(ex) do { \
46         if (!(ex)) gc_abort(); \
47 } while (0)
48 #else
49 #define gc_assert(ex)
50 #endif
51
52 \f
53 /* These hold the original end of the read_only and static spaces so
54  * we can tell what are forwarding pointers. */
55
56 static lispobj *read_only_end, *static_end;
57
58 static lispobj *read_only_free, *static_free;
59
60 static lispobj *pscav(lispobj *addr, int nwords, boolean constant);
61
62 #define LATERBLOCKSIZE 1020
63 #define LATERMAXCOUNT 10
64
65 static struct
66 later {
67     struct later *next;
68     union {
69         lispobj *ptr;
70         int count;
71     } u[LATERBLOCKSIZE];
72 } *later_blocks = NULL;
73 static int later_count = 0;
74
75 #define CEILING(x,y) (((x) + ((y) - 1)) & (~((y) - 1)))
76 #define NWORDS(x,y) (CEILING((x),(y)) / (y))
77
78 #ifdef sparc
79 #define RAW_ADDR_OFFSET 0
80 #else
81 #define RAW_ADDR_OFFSET (6*sizeof(lispobj) - type_FunctionPointer)
82 #endif
83 \f
84 static boolean
85 forwarding_pointer_p(lispobj obj)
86 {
87     lispobj *ptr;
88
89     ptr = (lispobj *)obj;
90
91     return ((static_end <= ptr && ptr <= static_free) ||
92             (read_only_end <= ptr && ptr <= read_only_free));
93 }
94
95 static boolean
96 dynamic_pointer_p(lispobj ptr)
97 {
98 #ifndef __i386__
99     /* KLUDGE: This has an implicit dependence on the ordering of
100      * address spaces, and is therefore basically wrong. I'd fix it,
101      * but I don't have a non-386 port to test it on. Porters are
102      * encouraged to fix it. -- WHN 2000-10-17 */
103     return (ptr >= (lispobj)DYNAMIC_SPACE_START);
104 #else
105     /* Be more conservative, and remember, this is a maybe. */
106     return (ptr >= (lispobj)DYNAMIC_SPACE_START
107             &&
108             ptr < (lispobj)dynamic_space_free_pointer);
109 #endif
110 }
111
112 \f
113 #ifdef __i386__
114
115 #ifdef WANT_CGC
116 /* original x86/CGC stack scavenging code by Paul Werkowski */
117
118 static int
119 maybe_can_move_p(lispobj thing)
120 {
121     lispobj *thingp,header;
122     if (dynamic_pointer_p(thing)) { /* in dynamic space */
123         thingp = (lispobj*)PTR(thing);
124         header = *thingp;
125         if (Pointerp(header) && forwarding_pointer_p(header)) {
126             return -1;          /* must change it */
127         } else if (LowtagOf(thing) == type_ListPointer) {
128             return type_ListPointer;    /* can we check this somehow */
129         } else if (thing & 3) { /* not fixnum */
130             int kind = TypeOf(header);
131             /* printf(" %x %x",header,kind); */
132             switch (kind) {             /* something with a header */
133             case type_Bignum:
134             case type_SingleFloat:
135             case type_DoubleFloat:
136 #ifdef type_LongFloat
137             case type_LongFloat:
138 #endif
139             case type_Sap:
140             case type_SimpleVector:
141             case type_SimpleString:
142             case type_SimpleBitVector:
143             case type_SimpleArrayUnsignedByte2:
144             case type_SimpleArrayUnsignedByte4:
145             case type_SimpleArrayUnsignedByte8:
146             case type_SimpleArrayUnsignedByte16:
147             case type_SimpleArrayUnsignedByte32:
148 #ifdef type_SimpleArraySignedByte8
149             case type_SimpleArraySignedByte8:
150 #endif
151 #ifdef type_SimpleArraySignedByte16
152             case type_SimpleArraySignedByte16:
153 #endif
154 #ifdef type_SimpleArraySignedByte30
155             case type_SimpleArraySignedByte30:
156 #endif
157 #ifdef type_SimpleArraySignedByte32
158             case type_SimpleArraySignedByte32:
159 #endif
160             case type_SimpleArraySingleFloat:
161             case type_SimpleArrayDoubleFloat:
162 #ifdef type_SimpleArrayLongFloat
163             case type_SimpleArrayLongFloat:
164 #endif
165 #ifdef type_SimpleArrayComplexSingleFloat
166             case type_SimpleArrayComplexSingleFloat:
167 #endif
168 #ifdef type_SimpleArrayComplexDoubleFloat
169             case type_SimpleArrayComplexDoubleFloat:
170 #endif
171 #ifdef type_SimpleArrayComplexLongFloat
172             case type_SimpleArrayComplexLongFloat:
173 #endif
174             case type_CodeHeader:
175             case type_FunctionHeader:
176             case type_ClosureFunctionHeader:
177             case type_ReturnPcHeader:
178             case type_ClosureHeader:
179             case type_FuncallableInstanceHeader:
180             case type_InstanceHeader:
181             case type_ValueCellHeader:
182             case type_ByteCodeFunction:
183             case type_ByteCodeClosure:
184             case type_WeakPointer:
185             case type_Fdefn:
186                 return kind;
187                 break;
188             default:
189                 return 0;
190             }
191         }
192     }
193     return 0;
194 }
195
196 static int pverbose=0;
197 #define PVERBOSE pverbose
198 static void
199 carefully_pscav_stack(lispobj*lowaddr, lispobj*base)
200 {
201     lispobj *sp = lowaddr;
202     while (sp < base) {
203         int k;
204         lispobj thing = *sp;
205         if ((unsigned)thing & 0x3) {    /* may be pointer */
206             /* need to check for valid float/double? */
207             k = maybe_can_move_p(thing);
208             if(PVERBOSE)printf("%8x %8x %d\n",sp, thing, k);
209             if(k)
210                 pscav(sp, 1, 0);
211         }
212         sp++;
213     }
214 }
215 #endif
216
217 #ifdef GENCGC
218 /*
219  * enhanced x86/GENCGC stack scavenging by Douglas Crosher
220  *
221  * Scavenging the stack on the i386 is problematic due to conservative
222  * roots and raw return addresses. Here it is handled in two passes:
223  * the first pass runs before any objects are moved and tries to
224  * identify valid pointers and return address on the stack, the second
225  * pass scavenges these.
226  */
227
228 static unsigned pointer_filter_verbose = 0;
229
230 static int
231 valid_dynamic_space_pointer(lispobj *pointer, lispobj *start_addr)
232 {
233     /* If it's not a return address then it needs to be a valid Lisp
234      * pointer. */
235     if (!Pointerp((lispobj)pointer))
236         return 0;
237
238     /* Check that the object pointed to is consistent with the pointer
239      * low tag. */
240     switch (LowtagOf((lispobj)pointer)) {
241     case type_FunctionPointer:
242         /* Start_addr should be the enclosing code object, or a closure
243          * header. */
244         switch (TypeOf(*start_addr)) {
245         case type_CodeHeader:
246             /* This case is probably caught above. */
247             break;
248         case type_ClosureHeader:
249         case type_FuncallableInstanceHeader:
250         case type_ByteCodeFunction:
251         case type_ByteCodeClosure:
252             if ((int)pointer != ((int)start_addr+type_FunctionPointer)) {
253                 if (pointer_filter_verbose) {
254                     fprintf(stderr,"*Wf2: %x %x %x\n", (unsigned int) pointer, 
255                             (unsigned int) start_addr, *start_addr);
256                 }
257                 return 0;
258             }
259             break;
260         default:
261             if (pointer_filter_verbose) {
262                 fprintf(stderr,"*Wf3: %x %x %x\n", (unsigned int) pointer, 
263                         (unsigned int) start_addr, *start_addr);
264             }
265             return 0;
266         }
267         break;
268     case type_ListPointer:
269         if ((int)pointer != ((int)start_addr+type_ListPointer)) {
270             if (pointer_filter_verbose)
271                 fprintf(stderr,"*Wl1: %x %x %x\n", (unsigned int) pointer, 
272                         (unsigned int) start_addr, *start_addr);
273             return 0;
274         }
275         /* Is it plausible cons? */
276         if((Pointerp(start_addr[0])
277             || ((start_addr[0] & 3) == 0) /* fixnum */
278             || (TypeOf(start_addr[0]) == type_BaseChar)
279             || (TypeOf(start_addr[0]) == type_UnboundMarker))
280            && (Pointerp(start_addr[1])
281                || ((start_addr[1] & 3) == 0) /* fixnum */
282                || (TypeOf(start_addr[1]) == type_BaseChar)
283                || (TypeOf(start_addr[1]) == type_UnboundMarker))) {
284             break;
285         } else {
286             if (pointer_filter_verbose) {
287                 fprintf(stderr,"*Wl2: %x %x %x\n", (unsigned int) pointer, 
288                         (unsigned int) start_addr, *start_addr);
289             }
290             return 0;
291         }
292     case type_InstancePointer:
293         if ((int)pointer != ((int)start_addr+type_InstancePointer)) {
294             if (pointer_filter_verbose) {
295                 fprintf(stderr,"*Wi1: %x %x %x\n", (unsigned int) pointer, 
296                         (unsigned int) start_addr, *start_addr);
297             }
298             return 0;
299         }
300         if (TypeOf(start_addr[0]) != type_InstanceHeader) {
301             if (pointer_filter_verbose) {
302                 fprintf(stderr,"*Wi2: %x %x %x\n", (unsigned int) pointer, 
303                         (unsigned int) start_addr, *start_addr);
304             }
305             return 0;
306         }
307         break;
308     case type_OtherPointer:
309         if ((int)pointer != ((int)start_addr+type_OtherPointer)) {
310             if (pointer_filter_verbose) {
311                 fprintf(stderr,"*Wo1: %x %x %x\n", (unsigned int) pointer, 
312                         (unsigned int) start_addr, *start_addr);
313             }
314             return 0;
315         }
316         /* Is it plausible?  Not a cons. X should check the headers. */
317         if(Pointerp(start_addr[0]) || ((start_addr[0] & 3) == 0)) {
318             if (pointer_filter_verbose) {
319                 fprintf(stderr,"*Wo2: %x %x %x\n", (unsigned int) pointer, 
320                         (unsigned int) start_addr, *start_addr);
321             }
322             return 0;
323         }
324         switch (TypeOf(start_addr[0])) {
325         case type_UnboundMarker:
326         case type_BaseChar:
327             if (pointer_filter_verbose) {
328                 fprintf(stderr,"*Wo3: %x %x %x\n", (unsigned int) pointer, 
329                         (unsigned int) start_addr, *start_addr);
330             }
331             return 0;
332
333             /* only pointed to by function pointers? */
334         case type_ClosureHeader:
335         case type_FuncallableInstanceHeader:
336         case type_ByteCodeFunction:
337         case type_ByteCodeClosure:
338             if (pointer_filter_verbose) {
339                 fprintf(stderr,"*Wo4: %x %x %x\n", (unsigned int) pointer, 
340                         (unsigned int) start_addr, *start_addr);
341             }
342             return 0;
343
344         case type_InstanceHeader:
345             if (pointer_filter_verbose) {
346                 fprintf(stderr,"*Wo5: %x %x %x\n", (unsigned int) pointer, 
347                         (unsigned int) start_addr, *start_addr);
348             }
349             return 0;
350
351             /* the valid other immediate pointer objects */
352         case type_SimpleVector:
353         case type_Ratio:
354         case type_Complex:
355 #ifdef type_ComplexSingleFloat
356         case type_ComplexSingleFloat:
357 #endif
358 #ifdef type_ComplexDoubleFloat
359         case type_ComplexDoubleFloat:
360 #endif
361 #ifdef type_ComplexLongFloat
362         case type_ComplexLongFloat:
363 #endif
364         case type_SimpleArray:
365         case type_ComplexString:
366         case type_ComplexBitVector:
367         case type_ComplexVector:
368         case type_ComplexArray:
369         case type_ValueCellHeader:
370         case type_SymbolHeader:
371         case type_Fdefn:
372         case type_CodeHeader:
373         case type_Bignum:
374         case type_SingleFloat:
375         case type_DoubleFloat:
376 #ifdef type_LongFloat
377         case type_LongFloat:
378 #endif
379         case type_SimpleString:
380         case type_SimpleBitVector:
381         case type_SimpleArrayUnsignedByte2:
382         case type_SimpleArrayUnsignedByte4:
383         case type_SimpleArrayUnsignedByte8:
384         case type_SimpleArrayUnsignedByte16:
385         case type_SimpleArrayUnsignedByte32:
386 #ifdef type_SimpleArraySignedByte8
387         case type_SimpleArraySignedByte8:
388 #endif
389 #ifdef type_SimpleArraySignedByte16
390         case type_SimpleArraySignedByte16:
391 #endif
392 #ifdef type_SimpleArraySignedByte30
393         case type_SimpleArraySignedByte30:
394 #endif
395 #ifdef type_SimpleArraySignedByte32
396         case type_SimpleArraySignedByte32:
397 #endif
398         case type_SimpleArraySingleFloat:
399         case type_SimpleArrayDoubleFloat:
400 #ifdef type_SimpleArrayLongFloat
401         case type_SimpleArrayLongFloat:
402 #endif
403 #ifdef type_SimpleArrayComplexSingleFloat
404         case type_SimpleArrayComplexSingleFloat:
405 #endif
406 #ifdef type_SimpleArrayComplexDoubleFloat
407         case type_SimpleArrayComplexDoubleFloat:
408 #endif
409 #ifdef type_SimpleArrayComplexLongFloat
410         case type_SimpleArrayComplexLongFloat:
411 #endif
412         case type_Sap:
413         case type_WeakPointer:
414             break;
415
416         default:
417             if (pointer_filter_verbose) {
418                 fprintf(stderr,"*Wo6: %x %x %x\n", (unsigned int) pointer, 
419                         (unsigned int) start_addr, *start_addr);
420             }
421             return 0;
422         }
423         break;
424     default:
425         if (pointer_filter_verbose) {
426             fprintf(stderr,"*W?: %x %x %x\n", (unsigned int) pointer, 
427                     (unsigned int) start_addr, *start_addr);
428         }
429         return 0;
430     }
431
432     /* looks good */
433     return 1;
434 }
435
436 #define MAX_STACK_POINTERS 256
437 lispobj *valid_stack_locations[MAX_STACK_POINTERS];
438 unsigned int num_valid_stack_locations;
439
440 #define MAX_STACK_RETURN_ADDRESSES 128
441 lispobj *valid_stack_ra_locations[MAX_STACK_RETURN_ADDRESSES];
442 lispobj *valid_stack_ra_code_objects[MAX_STACK_RETURN_ADDRESSES];
443 unsigned int num_valid_stack_ra_locations;
444
445 /* Identify valid stack slots. */
446 static void
447 setup_i386_stack_scav(lispobj *lowaddr, lispobj *base)
448 {
449     lispobj *sp = lowaddr;
450     num_valid_stack_locations = 0;
451     num_valid_stack_ra_locations = 0;
452     for (sp = lowaddr; sp < base; sp++) {
453         lispobj thing = *sp;
454         /* Find the object start address */
455         lispobj *start_addr = search_dynamic_space((void *)thing);
456         if (start_addr) {
457             /* We need to allow raw pointers into Code objects for
458              * return addresses. This will also pick up pointers to
459              * functions in code objects. */
460             if (TypeOf(*start_addr) == type_CodeHeader) {
461                 gc_assert(num_valid_stack_ra_locations <
462                           MAX_STACK_RETURN_ADDRESSES);
463                 valid_stack_ra_locations[num_valid_stack_ra_locations] = sp;
464                 valid_stack_ra_code_objects[num_valid_stack_ra_locations++] =
465                     (lispobj *)((int)start_addr + type_OtherPointer);
466             } else {
467                 if (valid_dynamic_space_pointer((void *)thing, start_addr)) {
468                     gc_assert(num_valid_stack_locations < MAX_STACK_POINTERS);
469                     valid_stack_locations[num_valid_stack_locations++] = sp;
470                 }
471             }
472         }
473     }
474     if (pointer_filter_verbose) {
475         fprintf(stderr, "number of valid stack pointers = %d\n",
476                 num_valid_stack_locations);
477         fprintf(stderr, "number of stack return addresses = %d\n",
478                 num_valid_stack_ra_locations);
479     }
480 }
481
482 static void
483 pscav_i386_stack(void)
484 {
485     int i;
486
487     for (i = 0; i < num_valid_stack_locations; i++)
488         pscav(valid_stack_locations[i], 1, 0);
489
490     for (i = 0; i < num_valid_stack_ra_locations; i++) {
491         lispobj code_obj = (lispobj)valid_stack_ra_code_objects[i];
492         pscav(&code_obj, 1, 0);
493         if (pointer_filter_verbose) {
494             fprintf(stderr,"*C moved RA %x to %x; for code object %x to %x\n",
495                     *valid_stack_ra_locations[i],
496                     (int)(*valid_stack_ra_locations[i])
497                     - ((int)valid_stack_ra_code_objects[i] - (int)code_obj),
498                     (unsigned int) valid_stack_ra_code_objects[i], code_obj);
499         }
500         *valid_stack_ra_locations[i] =
501             ((int)(*valid_stack_ra_locations[i])
502              - ((int)valid_stack_ra_code_objects[i] - (int)code_obj));
503     }
504 }
505 #endif
506 #endif
507
508 \f
509 static void
510 pscav_later(lispobj *where, int count)
511 {
512     struct later *new;
513
514     if (count > LATERMAXCOUNT) {
515         while (count > LATERMAXCOUNT) {
516             pscav_later(where, LATERMAXCOUNT);
517             count -= LATERMAXCOUNT;
518             where += LATERMAXCOUNT;
519         }
520     }
521     else {
522         if (later_blocks == NULL || later_count == LATERBLOCKSIZE ||
523             (later_count == LATERBLOCKSIZE-1 && count > 1)) {
524             new  = (struct later *)malloc(sizeof(struct later));
525             new->next = later_blocks;
526             if (later_blocks && later_count < LATERBLOCKSIZE)
527                 later_blocks->u[later_count].ptr = NULL;
528             later_blocks = new;
529             later_count = 0;
530         }
531
532         if (count != 1)
533             later_blocks->u[later_count++].count = count;
534         later_blocks->u[later_count++].ptr = where;
535     }
536 }
537
538 static lispobj
539 ptrans_boxed(lispobj thing, lispobj header, boolean constant)
540 {
541     int nwords;
542     lispobj result, *new, *old;
543
544     nwords = 1 + HeaderValue(header);
545
546     /* Allocate it */
547     old = (lispobj *)PTR(thing);
548     if (constant) {
549         new = read_only_free;
550         read_only_free += CEILING(nwords, 2);
551     }
552     else {
553         new = static_free;
554         static_free += CEILING(nwords, 2);
555     }
556
557     /* Copy it. */
558     bcopy(old, new, nwords * sizeof(lispobj));
559
560     /* Deposit forwarding pointer. */
561     result = (lispobj)new | LowtagOf(thing);
562     *old = result;
563
564     /* Scavenge it. */
565     pscav(new, nwords, constant);
566
567     return result;
568 }
569
570 /* We need to look at the layout to see whether it is a pure structure
571  * class, and only then can we transport as constant. If it is pure,
572  * we can ALWAYS transport as a constant. */
573 static lispobj
574 ptrans_instance(lispobj thing, lispobj header, boolean constant)
575 {
576     lispobj layout = ((struct instance *)PTR(thing))->slots[0];
577     lispobj pure = ((struct instance *)PTR(layout))->slots[15];
578
579     switch (pure) {
580     case T:
581         return (ptrans_boxed(thing, header, 1));
582     case NIL:
583         return (ptrans_boxed(thing, header, 0));
584     case 0:
585         {
586             /* Substructure: special case for the COMPACT-INFO-ENVs,
587              * where the instance may have a point to the dynamic
588              * space placed into it (e.g. the cache-name slot), but
589              * the lists and arrays at the time of a purify can be
590              * moved to the RO space. */
591             int nwords;
592             lispobj result, *new, *old;
593
594             nwords = 1 + HeaderValue(header);
595
596             /* Allocate it */
597             old = (lispobj *)PTR(thing);
598             new = static_free;
599             static_free += CEILING(nwords, 2);
600
601             /* Copy it. */
602             bcopy(old, new, nwords * sizeof(lispobj));
603
604             /* Deposit forwarding pointer. */
605             result = (lispobj)new | LowtagOf(thing);
606             *old = result;
607
608             /* Scavenge it. */
609             pscav(new, nwords, 1);
610
611             return result;
612         }
613     default:
614         gc_abort();
615         return NIL; /* dummy value: return something ... */
616     }
617 }
618
619 static lispobj
620 ptrans_fdefn(lispobj thing, lispobj header)
621 {
622     int nwords;
623     lispobj result, *new, *old, oldfn;
624     struct fdefn *fdefn;
625
626     nwords = 1 + HeaderValue(header);
627
628     /* Allocate it */
629     old = (lispobj *)PTR(thing);
630     new = static_free;
631     static_free += CEILING(nwords, 2);
632
633     /* Copy it. */
634     bcopy(old, new, nwords * sizeof(lispobj));
635
636     /* Deposit forwarding pointer. */
637     result = (lispobj)new | LowtagOf(thing);
638     *old = result;
639
640     /* Scavenge the function. */
641     fdefn = (struct fdefn *)new;
642     oldfn = fdefn->function;
643     pscav(&fdefn->function, 1, 0);
644     if ((char *)oldfn + RAW_ADDR_OFFSET == fdefn->raw_addr)
645         fdefn->raw_addr = (char *)fdefn->function + RAW_ADDR_OFFSET;
646
647     return result;
648 }
649
650 static lispobj
651 ptrans_unboxed(lispobj thing, lispobj header)
652 {
653     int nwords;
654     lispobj result, *new, *old;
655
656     nwords = 1 + HeaderValue(header);
657
658     /* Allocate it */
659     old = (lispobj *)PTR(thing);
660     new = read_only_free;
661     read_only_free += CEILING(nwords, 2);
662
663     /* Copy it. */
664     bcopy(old, new, nwords * sizeof(lispobj));
665
666     /* Deposit forwarding pointer. */
667     result = (lispobj)new | LowtagOf(thing);
668     *old = result;
669
670     return result;
671 }
672
673 static lispobj
674 ptrans_vector(lispobj thing, int bits, int extra,
675               boolean boxed, boolean constant)
676 {
677     struct vector *vector;
678     int nwords;
679     lispobj result, *new;
680
681     vector = (struct vector *)PTR(thing);
682     nwords = 2 + (CEILING((fixnum_value(vector->length)+extra)*bits,32)>>5);
683
684     if (boxed && !constant) {
685         new = static_free;
686         static_free += CEILING(nwords, 2);
687     }
688     else {
689         new = read_only_free;
690         read_only_free += CEILING(nwords, 2);
691     }
692
693     bcopy(vector, new, nwords * sizeof(lispobj));
694
695     result = (lispobj)new | LowtagOf(thing);
696     vector->header = result;
697
698     if (boxed)
699         pscav(new, nwords, constant);
700
701     return result;
702 }
703
704 #ifdef __i386__
705 static void
706 apply_code_fixups_during_purify(struct code *old_code, struct code *new_code)
707 {
708   int nheader_words, ncode_words, nwords;
709   void  *constants_start_addr, *constants_end_addr;
710   void  *code_start_addr, *code_end_addr;
711   lispobj fixups = NIL;
712   unsigned  displacement = (unsigned)new_code - (unsigned)old_code;
713   struct vector *fixups_vector;
714
715   /* Byte compiled code has no fixups. The trace table offset will be
716    * a fixnum if it's x86 compiled code - check. */
717   if (new_code->trace_table_offset & 0x3)
718     return;
719
720   /* Else it's x86 machine code. */
721   ncode_words = fixnum_value(new_code->code_size);
722   nheader_words = HeaderValue(*(lispobj *)new_code);
723   nwords = ncode_words + nheader_words;
724
725   constants_start_addr = (void *)new_code + 5*4;
726   constants_end_addr = (void *)new_code + nheader_words*4;
727   code_start_addr = (void *)new_code + nheader_words*4;
728   code_end_addr = (void *)new_code + nwords*4;
729
730   /* The first constant should be a pointer to the fixups for this
731    * code objects. Check. */
732   fixups = new_code->constants[0];
733
734   /* It will be 0 or the unbound-marker if there are no fixups, and
735    * will be an other-pointer to a vector if it is valid. */
736   if ((fixups==0) || (fixups==type_UnboundMarker) || !Pointerp(fixups)) {
737 #ifdef GENCGC
738     /* Check for a possible errors. */
739     sniff_code_object(new_code,displacement);
740 #endif
741     return;
742   }
743
744   fixups_vector = (struct vector *)PTR(fixups);
745
746   /* Could be pointing to a forwarding pointer. */
747   if (Pointerp(fixups) && (dynamic_pointer_p(fixups))
748       && forwarding_pointer_p(*(lispobj *)fixups_vector)) {
749     /* If so then follow it. */
750     fixups_vector = (struct vector *)PTR(*(lispobj *)fixups_vector);
751   }
752
753   if (TypeOf(fixups_vector->header) == type_SimpleArrayUnsignedByte32) {
754     /* We got the fixups for the code block. Now work through the vector,
755      * and apply a fixup at each address. */
756     int length = fixnum_value(fixups_vector->length);
757     int i;
758     for (i=0; i<length; i++) {
759       unsigned offset = fixups_vector->data[i];
760       /* Now check the current value of offset. */
761       unsigned  old_value = *(unsigned *)((unsigned)code_start_addr + offset);
762
763       /* If it's within the old_code object then it must be an
764        * absolute fixup (relative ones are not saved) */
765       if ((old_value>=(unsigned)old_code)
766           && (old_value<((unsigned)old_code + nwords*4)))
767         /* So add the dispacement. */
768         *(unsigned *)((unsigned)code_start_addr + offset) = old_value
769           + displacement;
770       else
771         /* It is outside the old code object so it must be a relative
772          * fixup (absolute fixups are not saved). So subtract the
773          * displacement. */
774         *(unsigned *)((unsigned)code_start_addr + offset) = old_value
775           - displacement;
776     }
777   }
778
779   /* No longer need the fixups. */
780   new_code->constants[0] = 0;
781
782 #ifdef GENCGC
783   /* Check for possible errors. */
784   sniff_code_object(new_code,displacement);
785 #endif
786 }
787 #endif
788
789 static lispobj
790 ptrans_code(lispobj thing)
791 {
792     struct code *code, *new;
793     int nwords;
794     lispobj func, result;
795
796     code = (struct code *)PTR(thing);
797     nwords = HeaderValue(code->header) + fixnum_value(code->code_size);
798
799     new = (struct code *)read_only_free;
800     read_only_free += CEILING(nwords, 2);
801
802     bcopy(code, new, nwords * sizeof(lispobj));
803
804 #ifdef __i386__
805     apply_code_fixups_during_purify(code,new);
806 #endif
807
808     result = (lispobj)new | type_OtherPointer;
809
810     /* Stick in a forwarding pointer for the code object. */
811     *(lispobj *)code = result;
812
813     /* Put in forwarding pointers for all the functions. */
814     for (func = code->entry_points;
815          func != NIL;
816          func = ((struct function *)PTR(func))->next) {
817
818         gc_assert(LowtagOf(func) == type_FunctionPointer);
819
820         *(lispobj *)PTR(func) = result + (func - thing);
821     }
822
823     /* Arrange to scavenge the debug info later. */
824     pscav_later(&new->debug_info, 1);
825
826     if(new->trace_table_offset & 0x3)
827 #if 0
828       pscav(&new->trace_table_offset, 1, 0);
829 #else
830       new->trace_table_offset = NIL; /* limit lifetime */
831 #endif
832
833     /* Scavenge the constants. */
834     pscav(new->constants, HeaderValue(new->header)-5, 1);
835
836     /* Scavenge all the functions. */
837     pscav(&new->entry_points, 1, 1);
838     for (func = new->entry_points;
839          func != NIL;
840          func = ((struct function *)PTR(func))->next) {
841         gc_assert(LowtagOf(func) == type_FunctionPointer);
842         gc_assert(!dynamic_pointer_p(func));
843
844 #ifdef __i386__
845         /* Temporarly convert the self pointer to a real function
846            pointer. */
847         ((struct function *)PTR(func))->self -= RAW_ADDR_OFFSET;
848 #endif
849         pscav(&((struct function *)PTR(func))->self, 2, 1);
850 #ifdef __i386__
851         ((struct function *)PTR(func))->self += RAW_ADDR_OFFSET;
852 #endif
853         pscav_later(&((struct function *)PTR(func))->name, 3);
854     }
855
856     return result;
857 }
858
859 static lispobj
860 ptrans_func(lispobj thing, lispobj header)
861 {
862     int nwords;
863     lispobj code, *new, *old, result;
864     struct function *function;
865
866     /* Thing can either be a function header, a closure function
867      * header, a closure, or a funcallable-instance. If it's a closure
868      * or a funcallable-instance, we do the same as ptrans_boxed.
869      * Otherwise we have to do something strange, 'cause it is buried
870      * inside a code object. */
871
872     if (TypeOf(header) == type_FunctionHeader ||
873         TypeOf(header) == type_ClosureFunctionHeader) {
874
875         /* We can only end up here if the code object has not been
876          * scavenged, because if it had been scavenged, forwarding pointers
877          * would have been left behind for all the entry points. */
878
879         function = (struct function *)PTR(thing);
880         code = (PTR(thing)-(HeaderValue(function->header)*sizeof(lispobj))) |
881             type_OtherPointer;
882
883         /* This will cause the function's header to be replaced with a 
884          * forwarding pointer. */
885         ptrans_code(code);
886
887         /* So we can just return that. */
888         return function->header;
889     }
890     else {
891         /* It's some kind of closure-like thing. */
892         nwords = 1 + HeaderValue(header);
893         old = (lispobj *)PTR(thing);
894
895         /* Allocate the new one. */
896         if (TypeOf(header) == type_FuncallableInstanceHeader) {
897             /* FINs *must* not go in read_only space. */
898             new = static_free;
899             static_free += CEILING(nwords, 2);
900         }
901         else {
902             /* Closures can always go in read-only space, 'cause they
903              * never change. */
904
905             new = read_only_free;
906             read_only_free += CEILING(nwords, 2);
907         }
908         /* Copy it. */
909         bcopy(old, new, nwords * sizeof(lispobj));
910
911         /* Deposit forwarding pointer. */
912         result = (lispobj)new | LowtagOf(thing);
913         *old = result;
914
915         /* Scavenge it. */
916         pscav(new, nwords, 0);
917
918         return result;
919     }
920 }
921
922 static lispobj
923 ptrans_returnpc(lispobj thing, lispobj header)
924 {
925     lispobj code, new;
926
927     /* Find the corresponding code object. */
928     code = thing - HeaderValue(header)*sizeof(lispobj);
929
930     /* Make sure it's been transported. */
931     new = *(lispobj *)PTR(code);
932     if (!forwarding_pointer_p(new))
933         new = ptrans_code(code);
934
935     /* Maintain the offset: */
936     return new + (thing - code);
937 }
938
939 #define WORDS_PER_CONS CEILING(sizeof(struct cons) / sizeof(lispobj), 2)
940
941 static lispobj
942 ptrans_list(lispobj thing, boolean constant)
943 {
944     struct cons *old, *new, *orig;
945     int length;
946
947     if (constant)
948         orig = (struct cons *)read_only_free;
949     else
950         orig = (struct cons *)static_free;
951     length = 0;
952
953     do {
954         /* Allocate a new cons cell. */
955         old = (struct cons *)PTR(thing);
956         if (constant) {
957             new = (struct cons *)read_only_free;
958             read_only_free += WORDS_PER_CONS;
959         }
960         else {
961             new = (struct cons *)static_free;
962             static_free += WORDS_PER_CONS;
963         }
964
965         /* Copy the cons cell and keep a pointer to the cdr. */
966         new->car = old->car;
967         thing = new->cdr = old->cdr;
968
969         /* Set up the forwarding pointer. */
970         *(lispobj *)old = ((lispobj)new) | type_ListPointer;
971
972         /* And count this cell. */
973         length++;
974     } while (LowtagOf(thing) == type_ListPointer &&
975              dynamic_pointer_p(thing) &&
976              !(forwarding_pointer_p(*(lispobj *)PTR(thing))));
977
978     /* Scavenge the list we just copied. */
979     pscav((lispobj *)orig, length * WORDS_PER_CONS, constant);
980
981     return ((lispobj)orig) | type_ListPointer;
982 }
983
984 static lispobj
985 ptrans_otherptr(lispobj thing, lispobj header, boolean constant)
986 {
987     switch (TypeOf(header)) {
988       case type_Bignum:
989       case type_SingleFloat:
990       case type_DoubleFloat:
991 #ifdef type_LongFloat
992       case type_LongFloat:
993 #endif
994 #ifdef type_ComplexSingleFloat
995       case type_ComplexSingleFloat:
996 #endif
997 #ifdef type_ComplexDoubleFloat
998       case type_ComplexDoubleFloat:
999 #endif
1000 #ifdef type_ComplexLongFloat
1001       case type_ComplexLongFloat:
1002 #endif
1003       case type_Sap:
1004         return ptrans_unboxed(thing, header);
1005
1006       case type_Ratio:
1007       case type_Complex:
1008       case type_SimpleArray:
1009       case type_ComplexString:
1010       case type_ComplexVector:
1011       case type_ComplexArray:
1012         return ptrans_boxed(thing, header, constant);
1013         
1014       case type_ValueCellHeader:
1015       case type_WeakPointer:
1016         return ptrans_boxed(thing, header, 0);
1017
1018       case type_SymbolHeader:
1019         return ptrans_boxed(thing, header, 0);
1020
1021       case type_SimpleString:
1022         return ptrans_vector(thing, 8, 1, 0, constant);
1023
1024       case type_SimpleBitVector:
1025         return ptrans_vector(thing, 1, 0, 0, constant);
1026
1027       case type_SimpleVector:
1028         return ptrans_vector(thing, 32, 0, 1, constant);
1029
1030       case type_SimpleArrayUnsignedByte2:
1031         return ptrans_vector(thing, 2, 0, 0, constant);
1032
1033       case type_SimpleArrayUnsignedByte4:
1034         return ptrans_vector(thing, 4, 0, 0, constant);
1035
1036       case type_SimpleArrayUnsignedByte8:
1037 #ifdef type_SimpleArraySignedByte8
1038       case type_SimpleArraySignedByte8:
1039 #endif
1040         return ptrans_vector(thing, 8, 0, 0, constant);
1041
1042       case type_SimpleArrayUnsignedByte16:
1043 #ifdef type_SimpleArraySignedByte16
1044       case type_SimpleArraySignedByte16:
1045 #endif
1046         return ptrans_vector(thing, 16, 0, 0, constant);
1047
1048       case type_SimpleArrayUnsignedByte32:
1049 #ifdef type_SimpleArraySignedByte30
1050       case type_SimpleArraySignedByte30:
1051 #endif
1052 #ifdef type_SimpleArraySignedByte32
1053       case type_SimpleArraySignedByte32:
1054 #endif
1055         return ptrans_vector(thing, 32, 0, 0, constant);
1056
1057       case type_SimpleArraySingleFloat:
1058         return ptrans_vector(thing, 32, 0, 0, constant);
1059
1060       case type_SimpleArrayDoubleFloat:
1061         return ptrans_vector(thing, 64, 0, 0, constant);
1062
1063 #ifdef type_SimpleArrayLongFloat
1064       case type_SimpleArrayLongFloat:
1065 #ifdef __i386__
1066         return ptrans_vector(thing, 96, 0, 0, constant);
1067 #endif
1068 #ifdef sparc
1069         return ptrans_vector(thing, 128, 0, 0, constant);
1070 #endif
1071 #endif
1072
1073 #ifdef type_SimpleArrayComplexSingleFloat
1074       case type_SimpleArrayComplexSingleFloat:
1075         return ptrans_vector(thing, 64, 0, 0, constant);
1076 #endif
1077
1078 #ifdef type_SimpleArrayComplexDoubleFloat
1079       case type_SimpleArrayComplexDoubleFloat:
1080         return ptrans_vector(thing, 128, 0, 0, constant);
1081 #endif
1082
1083 #ifdef type_SimpleArrayComplexLongFloat
1084       case type_SimpleArrayComplexLongFloat:
1085 #ifdef __i386__
1086         return ptrans_vector(thing, 192, 0, 0, constant);
1087 #endif
1088 #ifdef sparc
1089         return ptrans_vector(thing, 256, 0, 0, constant);
1090 #endif
1091 #endif
1092
1093       case type_CodeHeader:
1094         return ptrans_code(thing);
1095
1096       case type_ReturnPcHeader:
1097         return ptrans_returnpc(thing, header);
1098
1099       case type_Fdefn:
1100         return ptrans_fdefn(thing, header);
1101
1102       default:
1103         /* Should only come across other pointers to the above stuff. */
1104         gc_abort();
1105         return NIL;
1106     }
1107 }
1108
1109 static int
1110 pscav_fdefn(struct fdefn *fdefn)
1111 {
1112     boolean fix_func;
1113
1114     fix_func = ((char *)(fdefn->function+RAW_ADDR_OFFSET) == fdefn->raw_addr);
1115     pscav(&fdefn->name, 1, 1);
1116     pscav(&fdefn->function, 1, 0);
1117     if (fix_func)
1118         fdefn->raw_addr = (char *)(fdefn->function + RAW_ADDR_OFFSET);
1119     return sizeof(struct fdefn) / sizeof(lispobj);
1120 }
1121
1122 #ifdef __i386__
1123 /* now putting code objects in static space */
1124 static int
1125 pscav_code(struct code*code)
1126 {
1127     int nwords;
1128     lispobj func;
1129     nwords = HeaderValue(code->header) + fixnum_value(code->code_size);
1130
1131     /* pw--The trace_table_offset slot can contain a list pointer. This
1132      * occurs when the code object is a top level form that initializes
1133      * a byte-compiled function. The fact that PURIFY was ignoring this
1134      * slot may be a bug unrelated to the x86 port, except that TLF's
1135      * normally become unreachable after the loader calls them and
1136      * won't be seen by PURIFY at all!! */
1137     if(code->trace_table_offset & 0x3)
1138 #if 0
1139       pscav(&code->trace_table_offset, 1, 0);
1140 #else
1141       code->trace_table_offset = NIL; /* limit lifetime */
1142 #endif
1143
1144     /* Arrange to scavenge the debug info later. */
1145     pscav_later(&code->debug_info, 1);
1146
1147     /* Scavenge the constants. */
1148     pscav(code->constants, HeaderValue(code->header)-5, 1);
1149
1150     /* Scavenge all the functions. */
1151     pscav(&code->entry_points, 1, 1);
1152     for (func = code->entry_points;
1153          func != NIL;
1154          func = ((struct function *)PTR(func))->next) {
1155         gc_assert(LowtagOf(func) == type_FunctionPointer);
1156         gc_assert(!dynamic_pointer_p(func));
1157
1158 #ifdef __i386__
1159         /* Temporarly convert the self pointer to a real function
1160          * pointer. */
1161         ((struct function *)PTR(func))->self -= RAW_ADDR_OFFSET;
1162 #endif
1163         pscav(&((struct function *)PTR(func))->self, 2, 1);
1164 #ifdef __i386__
1165         ((struct function *)PTR(func))->self += RAW_ADDR_OFFSET;
1166 #endif
1167         pscav_later(&((struct function *)PTR(func))->name, 3);
1168     }
1169
1170     return CEILING(nwords,2);
1171 }
1172 #endif
1173
1174 static lispobj *
1175 pscav(lispobj *addr, int nwords, boolean constant)
1176 {
1177     lispobj thing, *thingp, header;
1178     int count = 0; /* (0 = dummy init value to stop GCC warning) */
1179     struct vector *vector;
1180
1181     while (nwords > 0) {
1182         thing = *addr;
1183         if (Pointerp(thing)) {
1184             /* It's a pointer. Is it something we might have to move? */
1185             if (dynamic_pointer_p(thing)) {
1186                 /* Maybe. Have we already moved it? */
1187                 thingp = (lispobj *)PTR(thing);
1188                 header = *thingp;
1189                 if (Pointerp(header) && forwarding_pointer_p(header))
1190                     /* Yep, so just copy the forwarding pointer. */
1191                     thing = header;
1192                 else {
1193                     /* Nope, copy the object. */
1194                     switch (LowtagOf(thing)) {
1195                       case type_FunctionPointer:
1196                         thing = ptrans_func(thing, header);
1197                         break;
1198
1199                       case type_ListPointer:
1200                         thing = ptrans_list(thing, constant);
1201                         break;
1202
1203                       case type_InstancePointer:
1204                         thing = ptrans_instance(thing, header, constant);
1205                         break;
1206
1207                       case type_OtherPointer:
1208                         thing = ptrans_otherptr(thing, header, constant);
1209                         break;
1210
1211                       default:
1212                         /* It was a pointer, but not one of them? */
1213                         gc_abort();
1214                     }
1215                 }
1216                 *addr = thing;
1217             }
1218             count = 1;
1219         }
1220         else if (thing & 3) {
1221             /* It's an other immediate. Maybe the header for an unboxed */
1222             /* object. */
1223             switch (TypeOf(thing)) {
1224               case type_Bignum:
1225               case type_SingleFloat:
1226               case type_DoubleFloat:
1227 #ifdef type_LongFloat
1228               case type_LongFloat:
1229 #endif
1230               case type_Sap:
1231                 /* It's an unboxed simple object. */
1232                 count = HeaderValue(thing)+1;
1233                 break;
1234
1235               case type_SimpleVector:
1236                 if (HeaderValue(thing) == subtype_VectorValidHashing)
1237                     *addr = (subtype_VectorMustRehash<<type_Bits) |
1238                         type_SimpleVector;
1239                 count = 1;
1240                 break;
1241
1242               case type_SimpleString:
1243                 vector = (struct vector *)addr;
1244                 count = CEILING(NWORDS(fixnum_value(vector->length)+1,4)+2,2);
1245                 break;
1246
1247               case type_SimpleBitVector:
1248                 vector = (struct vector *)addr;
1249                 count = CEILING(NWORDS(fixnum_value(vector->length),32)+2,2);
1250                 break;
1251
1252               case type_SimpleArrayUnsignedByte2:
1253                 vector = (struct vector *)addr;
1254                 count = CEILING(NWORDS(fixnum_value(vector->length),16)+2,2);
1255                 break;
1256
1257               case type_SimpleArrayUnsignedByte4:
1258                 vector = (struct vector *)addr;
1259                 count = CEILING(NWORDS(fixnum_value(vector->length),8)+2,2);
1260                 break;
1261
1262               case type_SimpleArrayUnsignedByte8:
1263 #ifdef type_SimpleArraySignedByte8
1264               case type_SimpleArraySignedByte8:
1265 #endif
1266                 vector = (struct vector *)addr;
1267                 count = CEILING(NWORDS(fixnum_value(vector->length),4)+2,2);
1268                 break;
1269
1270               case type_SimpleArrayUnsignedByte16:
1271 #ifdef type_SimpleArraySignedByte16
1272               case type_SimpleArraySignedByte16:
1273 #endif
1274                 vector = (struct vector *)addr;
1275                 count = CEILING(NWORDS(fixnum_value(vector->length),2)+2,2);
1276                 break;
1277
1278               case type_SimpleArrayUnsignedByte32:
1279 #ifdef type_SimpleArraySignedByte30
1280               case type_SimpleArraySignedByte30:
1281 #endif
1282 #ifdef type_SimpleArraySignedByte32
1283               case type_SimpleArraySignedByte32:
1284 #endif
1285                 vector = (struct vector *)addr;
1286                 count = CEILING(fixnum_value(vector->length)+2,2);
1287                 break;
1288
1289               case type_SimpleArraySingleFloat:
1290                 vector = (struct vector *)addr;
1291                 count = CEILING(fixnum_value(vector->length)+2,2);
1292                 break;
1293
1294               case type_SimpleArrayDoubleFloat:
1295 #ifdef type_SimpleArrayComplexSingleFloat
1296               case type_SimpleArrayComplexSingleFloat:
1297 #endif
1298                 vector = (struct vector *)addr;
1299                 count = fixnum_value(vector->length)*2+2;
1300                 break;
1301
1302 #ifdef type_SimpleArrayLongFloat
1303               case type_SimpleArrayLongFloat:
1304                 vector = (struct vector *)addr;
1305 #ifdef __i386__
1306                 count = fixnum_value(vector->length)*3+2;
1307 #endif
1308 #ifdef sparc
1309                 count = fixnum_value(vector->length)*4+2;
1310 #endif
1311                 break;
1312 #endif
1313
1314 #ifdef type_SimpleArrayComplexDoubleFloat
1315               case type_SimpleArrayComplexDoubleFloat:
1316                 vector = (struct vector *)addr;
1317                 count = fixnum_value(vector->length)*4+2;
1318                 break;
1319 #endif
1320
1321 #ifdef type_SimpleArrayComplexLongFloat
1322               case type_SimpleArrayComplexLongFloat:
1323                 vector = (struct vector *)addr;
1324 #ifdef __i386__
1325                 count = fixnum_value(vector->length)*6+2;
1326 #endif
1327 #ifdef sparc
1328                 count = fixnum_value(vector->length)*8+2;
1329 #endif
1330                 break;
1331 #endif
1332
1333               case type_CodeHeader:
1334 #ifndef __i386__
1335                 gc_abort(); /* no code headers in static space */
1336 #else
1337                 count = pscav_code((struct code*)addr);
1338 #endif
1339                 break;
1340
1341               case type_FunctionHeader:
1342               case type_ClosureFunctionHeader:
1343               case type_ReturnPcHeader:
1344                 /* We should never hit any of these, 'cause they occur
1345                  * buried in the middle of code objects. */
1346                 gc_abort();
1347                 break;
1348
1349 #ifdef __i386__
1350               case type_ClosureHeader:
1351               case type_FuncallableInstanceHeader:
1352               case type_ByteCodeFunction:
1353               case type_ByteCodeClosure:
1354                 /* The function self pointer needs special care on the
1355                  * x86 because it is the real entry point. */
1356                 {
1357                   lispobj fun = ((struct closure *)addr)->function
1358                     - RAW_ADDR_OFFSET;
1359                   pscav(&fun, 1, constant);
1360                   ((struct closure *)addr)->function = fun + RAW_ADDR_OFFSET;
1361                 }
1362                 count = 2;
1363                 break;
1364 #endif
1365
1366               case type_WeakPointer:
1367                 /* Weak pointers get preserved during purify, 'cause I
1368                  * don't feel like figuring out how to break them. */
1369                 pscav(addr+1, 2, constant);
1370                 count = 4;
1371                 break;
1372
1373               case type_Fdefn:
1374                 /* We have to handle fdefn objects specially, so we
1375                  * can fix up the raw function address. */
1376                 count = pscav_fdefn((struct fdefn *)addr);
1377                 break;
1378
1379               default:
1380                 count = 1;
1381                 break;
1382             }
1383         }
1384         else {
1385             /* It's a fixnum. */
1386             count = 1;
1387         }
1388
1389         addr += count;
1390         nwords -= count;
1391     }
1392
1393     return addr;
1394 }
1395
1396 int
1397 purify(lispobj static_roots, lispobj read_only_roots)
1398 {
1399     lispobj *clean;
1400     int count, i;
1401     struct later *laters, *next;
1402
1403 #ifdef PRINTNOISE
1404     printf("[doing purification:");
1405     fflush(stdout);
1406 #endif
1407
1408     if (fixnum_value(SymbolValue(FREE_INTERRUPT_CONTEXT_INDEX)) != 0) {
1409         /* FIXME: 1. What does this mean? 2. It shouldn't be reporting
1410          * its error simply by a. printing a string b. to stdout instead
1411          * of stderr. */
1412         printf(" Ack! Can't purify interrupt contexts. ");
1413         fflush(stdout);
1414         return 0;
1415     }
1416
1417 #if defined(ibmrt) || defined(__i386__)
1418     dynamic_space_free_pointer =
1419       (lispobj*)SymbolValue(ALLOCATION_POINTER);
1420 #endif
1421
1422     read_only_end = read_only_free =
1423         (lispobj *)SymbolValue(READ_ONLY_SPACE_FREE_POINTER);
1424     static_end = static_free =
1425         (lispobj *)SymbolValue(STATIC_SPACE_FREE_POINTER);
1426
1427 #ifdef PRINTNOISE
1428     printf(" roots");
1429     fflush(stdout);
1430 #endif
1431
1432 #ifdef GENCGC
1433     gc_assert((lispobj *)CONTROL_STACK_END > ((&read_only_roots)+1));
1434     setup_i386_stack_scav(((&static_roots)-2), (lispobj *)CONTROL_STACK_END);
1435 #endif
1436
1437     pscav(&static_roots, 1, 0);
1438     pscav(&read_only_roots, 1, 1);
1439
1440 #ifdef PRINTNOISE
1441     printf(" handlers");
1442     fflush(stdout);
1443 #endif
1444     pscav((lispobj *) interrupt_handlers,
1445           sizeof(interrupt_handlers) / sizeof(lispobj),
1446           0);
1447
1448 #ifdef PRINTNOISE
1449     printf(" stack");
1450     fflush(stdout);
1451 #endif
1452 #ifndef __i386__
1453     pscav((lispobj *)CONTROL_STACK_START,
1454           current_control_stack_pointer - (lispobj *)CONTROL_STACK_START,
1455           0);
1456 #else
1457 #ifdef GENCGC
1458     pscav_i386_stack();
1459 #endif
1460 #ifdef WANT_CGC
1461     gc_assert((lispobj *)control_stack_end > ((&read_only_roots)+1));
1462     carefully_pscav_stack(((&read_only_roots)+1),
1463                           (lispobj *)CONTROL_STACK_END);
1464 #endif
1465 #endif
1466
1467 #ifdef PRINTNOISE
1468     printf(" bindings");
1469     fflush(stdout);
1470 #endif
1471 #if !defined(ibmrt) && !defined(__i386__)
1472     pscav( (lispobj *)BINDING_STACK_START,
1473           (lispobj *)current_binding_stack_pointer - (lispobj *)BINDING_STACK_START,
1474           0);
1475 #else
1476     pscav( (lispobj *)BINDING_STACK_START,
1477           (lispobj *)SymbolValue(BINDING_STACK_POINTER) -
1478           (lispobj *)BINDING_STACK_START,
1479           0);
1480 #endif
1481
1482 #ifdef SCAVENGE_READ_ONLY_SPACE
1483     if (SymbolValue(SCAVENGE_READ_ONLY_SPACE) != type_UnboundMarker
1484         && SymbolValue(SCAVENGE_READ_ONLY_SPACE) != NIL) {
1485       unsigned  read_only_space_size =
1486           (lispobj *)SymbolValue(READ_ONLY_SPACE_FREE_POINTER) -
1487           (lispobj *)READ_ONLY_SPACE_START;
1488       fprintf(stderr,
1489               "scavenging read only space: %d bytes\n",
1490               read_only_space_size * sizeof(lispobj));
1491       pscav( (lispobj *)READ_ONLY_SPACE_START, read_only_space_size, 0);
1492     }
1493 #endif
1494
1495 #ifdef PRINTNOISE
1496     printf(" static");
1497     fflush(stdout);
1498 #endif
1499     clean = (lispobj *)STATIC_SPACE_START;
1500     do {
1501         while (clean != static_free)
1502             clean = pscav(clean, static_free - clean, 0);
1503         laters = later_blocks;
1504         count = later_count;
1505         later_blocks = NULL;
1506         later_count = 0;
1507         while (laters != NULL) {
1508             for (i = 0; i < count; i++) {
1509                 if (laters->u[i].count == 0) {
1510                     ;
1511                 } else if (laters->u[i].count <= LATERMAXCOUNT) {
1512                     pscav(laters->u[i+1].ptr, laters->u[i].count, 1);
1513                     i++;
1514                 } else {
1515                     pscav(laters->u[i].ptr, 1, 1);
1516                 }
1517             }
1518             next = laters->next;
1519             free(laters);
1520             laters = next;
1521             count = LATERBLOCKSIZE;
1522         }
1523     } while (clean != static_free || later_blocks != NULL);
1524
1525 #ifdef PRINTNOISE
1526     printf(" cleanup");
1527     fflush(stdout);
1528 #endif
1529
1530 #if defined(WANT_CGC) && defined(X86_CGC_ACTIVE_P)
1531     if(SymbolValue(X86_CGC_ACTIVE_P) != T) {
1532         os_zero((os_vm_address_t) DYNAMIC_SPACE_START,
1533                 (os_vm_size_t) DYNAMIC_SPACE_SIZE);
1534     }
1535 #else
1536     os_zero((os_vm_address_t) current_dynamic_space,
1537             (os_vm_size_t) DYNAMIC_SPACE_SIZE);
1538 #endif
1539
1540     /* Zero the stack. Note that the stack is also zeroed by SUB-GC
1541      * calling SCRUB-CONTROL-STACK - this zeros the stack on the x86. */
1542 #ifndef __i386__
1543     os_zero((os_vm_address_t) current_control_stack_pointer,
1544             (os_vm_size_t) (CONTROL_STACK_SIZE -
1545                             ((current_control_stack_pointer -
1546                               (lispobj *)CONTROL_STACK_START) *
1547                              sizeof(lispobj))));
1548 #endif
1549
1550 #if defined(WANT_CGC) && defined(STATIC_BLUE_BAG)
1551     {
1552       lispobj bag = SymbolValue(STATIC_BLUE_BAG);
1553       struct cons*cons = (struct cons*)static_free;
1554       struct cons*pair = cons + 1;
1555       static_free += 2*WORDS_PER_CONS;
1556       if(bag == type_UnboundMarker)
1557         bag = NIL;
1558       cons->cdr = bag;
1559       cons->car = (lispobj)pair | type_ListPointer;
1560       pair->car = (lispobj)static_end;
1561       pair->cdr = (lispobj)static_free;
1562       bag = (lispobj)cons | type_ListPointer;
1563       SetSymbolValue(STATIC_BLUE_BAG, bag);
1564     }
1565 #endif
1566
1567     /* It helps to update the heap free pointers so that free_heap can
1568      * verify after it's done. */
1569     SetSymbolValue(READ_ONLY_SPACE_FREE_POINTER, (lispobj)read_only_free);
1570     SetSymbolValue(STATIC_SPACE_FREE_POINTER, (lispobj)static_free);
1571
1572 #if !defined(ibmrt) && !defined(__i386__)
1573     dynamic_space_free_pointer = current_dynamic_space;
1574 #else
1575 #if defined(WANT_CGC) && defined(X86_CGC_ACTIVE_P)
1576     /* X86 using CGC */
1577     if(SymbolValue(X86_CGC_ACTIVE_P) != T)
1578         SetSymbolValue(ALLOCATION_POINTER, (lispobj)DYNAMIC_SPACE_START);
1579     else
1580         cgc_free_heap();
1581 #else
1582 #if defined GENCGC
1583     gc_free_heap();
1584 #else
1585     /* ibmrt using GC */
1586     SetSymbolValue(ALLOCATION_POINTER, (lispobj)DYNAMIC_SPACE_START);
1587 #endif
1588 #endif
1589 #endif
1590
1591 #ifdef PRINTNOISE
1592     printf(" done]\n");
1593     fflush(stdout);
1594 #endif
1595
1596     return 0;
1597 }