Late-breaking NEWS for late-breaking fixes
[sbcl.git] / src / runtime / cheneygc.c
bloba8880f32dd03af4a4588e3aa825fde087946f43e
1 /*
2 * stop and copy GC based on Cheney's algorithm
3 */
5 /*
6 * This software is part of the SBCL system. See the README file for
7 * more information.
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.
16 #include <stdio.h>
17 #include <sys/time.h>
18 #include <sys/resource.h>
19 #include <signal.h>
20 #include <stdlib.h>
21 #include "genesis/sbcl.h"
22 #include "runtime.h"
23 #include "os.h"
24 #include "gc.h"
25 #include "globals.h"
26 #include "interrupt.h"
27 #include "validate.h"
28 #include "lispregs.h"
29 #include "interr.h"
30 #include "genesis/static-symbols.h"
31 #include "genesis/primitive-objects.h"
32 #include "thread.h"
33 #include "arch.h"
34 #include "code.h"
35 #include "private-cons.inc"
36 #include "pseudo-atomic.h"
37 #include "genesis/gc-tables.h" // for leaf_obj_widetag_p
39 /* So you need to debug? */
40 #if 0
41 #define PRINTNOISE
42 #define DEBUG_SPACE_PREDICATES
43 #define DEBUG_SCAVENGE_VERBOSE
44 #define DEBUG_COPY_VERBOSE
45 #endif
47 lispobj *from_space;
48 lispobj *from_space_free_pointer;
50 lispobj *new_space;
51 lispobj *new_space_free_pointer;
53 lispobj *current_dynamic_space;
55 /* This does nothing. It's only to satisfy a reference from gc-common. */
56 char gc_coalesce_string_literals = 0;
58 boolean gc_active_p = 0;
60 static void scavenge_newspace(void);
63 /* collecting garbage */
65 #ifdef PRINTNOISE
66 static double
67 tv_diff(struct timeval *x, struct timeval *y)
69 return (((double) x->tv_sec + (double) x->tv_usec * 1.0e-6) -
70 ((double) y->tv_sec + (double) y->tv_usec * 1.0e-6));
72 #endif
74 void *
75 gc_general_alloc(__attribute__((unused)) void* ignore,
76 sword_t bytes,
77 __attribute__((unused)) int page_type) {
78 lispobj *new=new_space_free_pointer;
79 new_space_free_pointer+=(bytes/N_WORD_BYTES);
80 return new;
83 lispobj copy_unboxed_object(lispobj object, sword_t nwords) {
84 return gc_copy_object(object, nwords, 0, 0);
86 lispobj copy_potential_large_object(lispobj object, sword_t nwords,
87 __attribute__((unused)) void* region,
88 __attribute__((unused)) int page_type) {
89 return gc_copy_object(object, nwords, 0, 0);
92 #if 0
93 static void verify_range(int purified, lispobj *base, lispobj *end);
94 void show_spaces()
96 fprintf(stderr, " R/O = %10p:%10p\n", (void*)READ_ONLY_SPACE_START, read_only_space_free_pointer);
97 fprintf(stderr, " static = %10p:%10p\n", (void*)STATIC_SPACE_START, static_space_free_pointer);
98 fprintf(stderr, " dynamic = %10p:%10p\n", current_dynamic_space, dynamic_space_free_pointer);
99 struct thread* th = all_threads;
100 fprintf(stderr, " stack = %10p:%10p\n",
101 th->control_stack_start,
102 access_control_stack_pointer(th));
104 void verify_heap(int purified)
106 show_spaces();
107 verify_range(purified, (lispobj*)READ_ONLY_SPACE_START, read_only_space_free_pointer);
108 verify_range(purified, (lispobj*)STATIC_SPACE_START, static_space_free_pointer);
109 if (!purified)
110 verify_range(0, current_dynamic_space, dynamic_space_free_pointer);
112 #endif
114 /* Note: The generic GC interface we're implementing passes us a
115 * last_generation argument. That's meaningless for us, since we're
116 * not a generational GC. So we ignore it. */
117 int n_gcs;
118 void
119 collect_garbage(generation_index_t ignore)
121 #ifdef PRINTNOISE
122 struct timeval start_tv, stop_tv;
123 struct rusage start_rusage, stop_rusage;
124 double real_time, system_time, user_time;
125 double percent_retained, gc_rate;
126 unsigned long size_discarded;
127 #endif
128 unsigned long size_retained;
129 lispobj *current_static_space_free_pointer;
130 sigset_t old;
131 struct thread *th=get_sb_vm_thread();
133 #ifdef PRINTNOISE
134 printf("[Collecting garbage ... \n");
136 getrusage(RUSAGE_SELF, &start_rusage);
137 gettimeofday(&start_tv, (struct timezone *) 0);
138 #endif
140 gc_active_p = 1;
142 /* it's possible that signals are blocked already if this was called
143 * from a signal handler (e.g. with the sigsegv gc_trigger stuff) */
144 block_blockable_signals(&old);
146 current_static_space_free_pointer = static_space_free_pointer;
148 /* Set up from space and new space pointers. */
150 // ++n_gcs; fprintf(stderr, "[%d] pre-verify:\n", n_gcs); verify_heap(0);
151 from_space = current_dynamic_space;
152 from_space_free_pointer = get_alloc_pointer();
154 #ifdef PRINTNOISE
155 fprintf(stderr,"from_space = %lx\n",
156 (unsigned long) current_dynamic_space);
157 #endif
158 if (current_dynamic_space == (lispobj *) DYNAMIC_0_SPACE_START)
159 new_space = (lispobj *)DYNAMIC_1_SPACE_START;
160 else if (current_dynamic_space == (lispobj *) DYNAMIC_1_SPACE_START)
161 new_space = (lispobj *) DYNAMIC_0_SPACE_START;
162 else {
163 lose("GC lossage. Current dynamic space is bogus!");
165 new_space_free_pointer = new_space;
167 /* Scavenge all of the roots. */
168 #ifdef PRINTNOISE
169 printf("Scavenging interrupt contexts ...\n");
170 #endif
171 scavenge_interrupt_contexts(th);
173 #ifdef PRINTNOISE
174 printf("Scavenging interrupt handlers ...\n");
175 #endif
176 scavenge(lisp_sig_handlers, NSIG);
178 #ifdef PRINTNOISE
179 printf("Scavenging the control stack ...\n");
180 #endif
181 scavenge_control_stack(th);
183 scav_binding_stack((lispobj*)th->binding_stack_start,
184 (lispobj*)get_binding_stack_pointer(th),
187 heap_scavenge(((lispobj *)STATIC_SPACE_START),
188 current_static_space_free_pointer);
189 scavenge(&lisp_package_vector, 1);
191 /* Scavenge newspace. */
192 #ifdef PRINTNOISE
193 printf("Scavenging new space (%d bytes) ...\n",
194 (int)((new_space_free_pointer - new_space) * sizeof(lispobj)));
195 #endif
196 scavenge_newspace();
199 #if defined(DEBUG_PRINT_GARBAGE)
200 print_garbage(from_space, from_space_free_pointer);
201 #endif
203 scan_binding_stack();
205 smash_weak_pointers();
206 gc_dispose_private_pages();
207 cull_weak_hash_tables(weak_ht_alivep_funs);
209 /* Flip spaces. */
210 #ifdef PRINTNOISE
211 printf("Flipping spaces ...\n");
212 #endif
214 /* Maybe FIXME: it's possible that we could significantly reduce
215 * RSS by zeroing the from_space or madvise(MADV_DONTNEED) or
216 * similar os-dependent tricks here */
217 os_zero((os_vm_address_t) from_space,
218 (os_vm_size_t) dynamic_space_size);
220 current_dynamic_space = new_space;
221 set_alloc_pointer((lispobj)new_space_free_pointer);
223 #ifdef PRINTNOISE
224 size_discarded = (from_space_free_pointer - from_space) * sizeof(lispobj);
225 #endif
226 size_retained = (new_space_free_pointer - new_space) * sizeof(lispobj);
228 os_flush_icache((os_vm_address_t)new_space, size_retained);
230 /* Zero stack. */
231 #ifdef PRINTNOISE
232 printf("Zeroing empty part of control stack ...\n");
233 #endif
234 scrub_control_stack();
235 set_auto_gc_trigger(size_retained+bytes_consed_between_gcs);
236 thread_sigmask(SIG_SETMASK, &old, 0);
238 gc_active_p = 0;
239 // fprintf(stderr, "post-verify:\n"); verify_heap(0);
241 #ifdef PRINTNOISE
242 gettimeofday(&stop_tv, (struct timezone *) 0);
243 getrusage(RUSAGE_SELF, &stop_rusage);
245 printf("done.]\n");
247 percent_retained = (((float) size_retained) /
248 ((float) size_discarded)) * 100.0;
250 printf("Total of %ld bytes out of %ld bytes retained (%3.2f%%).\n",
251 size_retained, size_discarded, percent_retained);
253 real_time = tv_diff(&stop_tv, &start_tv);
254 user_time = tv_diff(&stop_rusage.ru_utime, &start_rusage.ru_utime);
255 system_time = tv_diff(&stop_rusage.ru_stime, &start_rusage.ru_stime);
257 printf("Statistics: %10.2fs real, %10.2fs user, %10.2fs system.\n",
258 real_time, user_time, system_time);
260 gc_rate = ((float) size_retained / (float) (1<<20)) / real_time;
262 printf("%10.2f M bytes/sec collected.\n", gc_rate);
263 #endif
267 /* scavenging */
269 static void
270 scavenge_newspace(void)
272 lispobj *here, *next;
274 here = new_space;
276 do {
277 /* printf("here=%lx, new_space_free_pointer=%lx\n",
278 here,new_space_free_pointer); */
279 next = new_space_free_pointer;
280 heap_scavenge(here, next);
281 here = next;
282 } while (new_space_free_pointer > here ||
283 (test_weak_triggers(0, 0) && new_space_free_pointer > here));
284 /* printf("done with newspace\n"); */
287 /* debugging code */
289 void
290 print_garbage(lispobj *from_space, lispobj *from_space_free_pointer)
292 lispobj *start;
293 int total_words_not_copied;
295 printf("Scanning from space ...\n");
297 total_words_not_copied = 0;
298 start = from_space;
299 while (start < from_space_free_pointer) {
300 lispobj object;
301 int forwardp, type, nwords;
302 lispobj header;
304 object = *start;
305 forwardp = is_lisp_pointer(object) && new_space_p(object);
307 if (forwardp) {
308 int tag;
309 lispobj *pointer;
311 tag = lowtag_of(object);
313 switch (tag) {
314 case LIST_POINTER_LOWTAG:
315 nwords = 2;
316 break;
317 case INSTANCE_POINTER_LOWTAG:
318 printf("Don't know about instances yet!\n");
319 nwords = 1;
320 break;
321 case FUN_POINTER_LOWTAG:
322 nwords = 1;
323 break;
324 case OTHER_POINTER_LOWTAG:
325 pointer = native_pointer(object);
326 header = *pointer;
327 type = header_widetag(header);
328 nwords = (sizetab[type])(pointer);
329 break;
330 default: nwords=1; /* shut yer whinging, gcc */
332 } else {
333 type = header_widetag(object);
334 nwords = (sizetab[type])(start);
335 total_words_not_copied += nwords;
336 printf("%4d words not copied at 0x%16lx; ",
337 nwords, (unsigned long) start);
338 printf("Header word is 0x%08x\n",
339 (unsigned int) object);
341 start += nwords;
343 printf("%d total words not copied.\n", total_words_not_copied);
346 lispobj *
347 search_dynamic_space(void *pointer)
349 lispobj *start = (lispobj *) current_dynamic_space;
350 lispobj *end = get_alloc_pointer();
351 if ((pointer < (void *)start) || (pointer >= (void *)end))
352 return NULL;
353 return gc_search_space(start, pointer);
356 /* initialization. if gc_init can be moved to after core load, we could
357 * combine these two functions */
359 void
360 gc_init(void)
362 gc_common_init();
365 /* noise to manipulate the gc trigger stuff */
367 /* Functions that substantially change the dynamic space free pointer
368 * (collect_garbage, purify) are responsible also for resetting the
369 * auto_gc_trigger */
370 void set_auto_gc_trigger(os_vm_size_t dynamic_usage)
372 os_vm_address_t addr;
373 os_vm_size_t length;
375 addr = os_round_up_to_page((os_vm_address_t)current_dynamic_space
376 + dynamic_usage);
377 if (addr < (os_vm_address_t)get_alloc_pointer())
378 lose("set_auto_gc_trigger: tried to set gc trigger too low! (%ld < 0x%08lx)",
379 (unsigned long)dynamic_usage,
380 (unsigned long)((os_vm_address_t)get_alloc_pointer()
381 - (os_vm_address_t)current_dynamic_space));
383 if (dynamic_usage > dynamic_space_size)
384 lose("set_auto_gc_trigger: tried to set gc trigger too high! (0x%08lx)",
385 (unsigned long)dynamic_usage);
386 length = os_trunc_size_to_page(dynamic_space_size - dynamic_usage);
388 // range has to fall entirely within either semispace
389 uword_t semispace_0_end = DYNAMIC_0_SPACE_START + dynamic_space_size;
390 uword_t semispace_1_end = DYNAMIC_1_SPACE_START + dynamic_space_size;
391 uword_t end = (uword_t)addr + length - 1;
392 if (((uword_t)addr >= DYNAMIC_0_SPACE_START && end < semispace_0_end) ||
393 ((uword_t)addr >= DYNAMIC_1_SPACE_START && end < semispace_1_end)) {
394 #if defined(SUNOS) || defined(SOLARIS)
395 os_deallocate(addr, length);
396 #else
397 os_protect(addr, length, 0);
398 #endif
399 } else {
400 lose("auto_gc_trigger can't protect %p..%p (not owned)\n",
401 (void*)addr, (char*)end-1);
403 current_auto_gc_trigger = (lispobj *)addr;
406 void clear_auto_gc_trigger(void)
408 os_vm_address_t addr;
409 os_vm_size_t length;
411 if (current_auto_gc_trigger == NULL)
412 return;
414 addr = (os_vm_address_t)current_auto_gc_trigger;
415 length = dynamic_space_size + (os_vm_address_t)current_dynamic_space - addr;
417 #if defined(SUNOS) || defined(SOLARIS)
418 /* don't want to force whole space into swapping mode... */
419 os_validate(NOT_MOVABLE, addr, length);
420 #else
421 os_protect(addr, length, OS_VM_PROT_ALL);
422 #endif
424 current_auto_gc_trigger = NULL;
427 static boolean
428 gc_trigger_hit(void *addr)
430 if (current_auto_gc_trigger == NULL)
431 return 0;
432 else{
433 return (addr >= (void *)current_auto_gc_trigger &&
434 (char*)addr <((char *)current_dynamic_space + dynamic_space_size));
438 boolean
439 cheneygc_handle_wp_violation(os_context_t *context, void *addr)
441 if(!foreign_function_call_active && gc_trigger_hit(addr)){
442 struct thread *thread=get_sb_vm_thread();
443 clear_auto_gc_trigger();
444 /* Don't flood the system with interrupts if the need to gc is
445 * already noted. This can happen for example when SUB-GC
446 * allocates or after a gc triggered in a WITHOUT-GCING. */
447 if (SymbolValue(GC_PENDING,thread) == NIL) {
448 if (SymbolValue(GC_INHIBIT,thread) == NIL) {
449 if (arch_pseudo_atomic_atomic(context)) {
450 /* set things up so that GC happens when we finish
451 * the PA section */
452 SetSymbolValue(GC_PENDING,T,thread);
453 arch_set_pseudo_atomic_interrupted(context);
454 maybe_save_gc_mask_and_block_deferrables
455 (os_context_sigmask_addr(context));
456 } else {
457 maybe_gc(context);
459 } else {
460 SetSymbolValue(GC_PENDING,T,thread);
463 return 1;
465 return 0;
468 void gc_show_pte(lispobj obj)
470 printf("unimplemented\n");
473 sword_t scav_code_blob(lispobj *where, lispobj header)
475 struct code *code = (struct code *) where;
476 sword_t n_header_words = code_header_words(code);
478 /* Scavenge the boxed section of the code data block. */
479 scavenge(where + 2, n_header_words - 2);
480 /* And scavenge any 'self' pointers pointing outside of the object */
481 for_each_simple_fun(i, fun, code, 1, {
482 if (simplefun_is_wrapped(fun)) {
483 lispobj target_fun = fun_taggedptr_from_self(fun->self);
484 lispobj new = target_fun;
485 scavenge(&new, 1);
486 if (new != target_fun) fun->self = fun_self_from_taggedptr(new);
490 return code_total_nwords(code);
493 #if 0
494 static boolean in_stack_range_p(lispobj ptr)
496 struct thread* th = all_threads;
497 return (ptr >= (uword_t)th->control_stack_start &&
498 ptr < (uword_t)access_control_stack_pointer(th));
501 static boolean valid_space_p(int purified, lispobj ptr)
503 if ((ptr >= READ_ONLY_SPACE_START && ptr < (uword_t)read_only_space_free_pointer) ||
504 (ptr >= STATIC_SPACE_START && ptr < (uword_t)static_space_free_pointer) ||
505 (!purified &&
506 ((ptr >= (uword_t)current_dynamic_space && ptr < (uword_t)dynamic_space_free_pointer) ||
507 in_stack_range_p(ptr))))
508 return 1;
509 return 0;
512 void check_ptr(int purified, lispobj* where, lispobj ptr)
514 if (!is_lisp_pointer(ptr)) return;
516 if (!valid_space_p(purified, ptr)) {
517 fprintf(stderr, "Sus' pointer %p @ %p outside expected ranges\n",
518 (void*)ptr, where);
519 return;
522 // must be properly tagged
523 if (lowtag_of(ptr) == LIST_POINTER_LOWTAG) {
524 gc_assert(is_cons_half(CONS(ptr)->car));
525 gc_assert(is_cons_half(CONS(ptr)->cdr));
526 } else {
527 int widetag = widetag_of(native_pointer(ptr));
528 if (LOWTAG_FOR_WIDETAG(widetag) != lowtag_of(ptr) && !in_stack_range_p(ptr))
529 lose("Widetag/lowtag mismatch on %p", (void*)ptr);
533 #define CHECK_PTR(x,y) check_ptr(purified,x,y)
535 static void
536 verify_range(int purified, lispobj *base, lispobj *end)
538 lispobj* where = base;
539 int len, i;
540 lispobj layout;
541 for ( ; where < end ; where += object_size(where) ) {
542 if (is_cons_half(*where)) {
543 CHECK_PTR(where+0, where[0]);
544 CHECK_PTR(where+1, where[1]);
545 } else switch (widetag_of(where)) {
546 case INSTANCE_WIDETAG:
547 layout = instance_layout(where);
548 if (layout) {
549 gc_assert(layoutp(layout));
550 len = instance_length(*where);
551 struct bitmap bitmap = get_layout_bitmap(LAYOUT(layout));
552 for (i=0; i<len; ++i)
553 if (bitmap_logbitp(i, bitmap)) CHECK_PTR(where+i+1, where[1+i]);
555 break;
556 case CODE_HEADER_WIDETAG:
557 len = code_header_words((struct code*)where);
558 for(i=2; i<len; ++i) CHECK_PTR(where+i, where[i]);
559 break;
560 case FDEFN_WIDETAG:
561 CHECK_PTR(where+1, where[1]);
562 CHECK_PTR(where+2, where[2]);
563 CHECK_PTR(where+3, decode_fdefn_rawfun((struct fdefn*)where));
564 break;
565 case CLOSURE_WIDETAG:
566 case FUNCALLABLE_INSTANCE_WIDETAG:
567 // Scan the closure's trampoline word.
568 CHECK_PTR(where+1, fun_taggedptr_from_self(where[1]));
569 len = SHORT_BOXED_NWORDS(*where);
570 for(i=2; i<=len; ++i) CHECK_PTR(where+i, where[i]);
571 break;
572 default:
573 if (!leaf_obj_widetag_p(widetag_of(where))) {
574 int size = sizetab[widetag_of(where)](where);
575 for(i=1; i<size; ++i) CHECK_PTR(where+i, where[i]);
581 void dump_space_to_file(lispobj* where, lispobj* limit, char* pathname)
583 FILE *f;
584 f = fopen(pathname, "w");
585 while (where < limit) {
586 fprintf(f, "%p: %x\n", where, *where);
587 where += object_size(where);
589 fprintf(f, "--\n");
590 fclose(f);
592 #endif