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