diff options
Diffstat (limited to 'mark.c')
-rw-r--r-- | mark.c | 253 |
1 files changed, 144 insertions, 109 deletions
@@ -17,8 +17,7 @@ # include <stdio.h> -# include "private/gc_priv.h" -# include "private/gc_mark.h" +# include "private/gc_pmark.h" /* We put this here to minimize the risk of inlining. */ /*VARARGS*/ @@ -47,25 +46,21 @@ word GC_n_mark_procs = GC_RESERVED_MARK_PROCS; /* It's done here, since we need to deal with mark descriptors. */ struct obj_kind GC_obj_kinds[MAXOBJKINDS] = { /* PTRFREE */ { &GC_aobjfreelist[0], 0 /* filled in dynamically */, - 0 | DS_LENGTH, FALSE, FALSE }, + 0 | GC_DS_LENGTH, FALSE, FALSE }, /* NORMAL */ { &GC_objfreelist[0], 0, -# if defined(ADD_BYTE_AT_END) && ALIGNMENT > DS_TAGS - (word)(-ALIGNMENT) | DS_LENGTH, -# else - 0 | DS_LENGTH, -# endif + 0 | GC_DS_LENGTH, /* Adjusted in GC_init_inner for EXTRA_BYTES */ TRUE /* add length to descr */, TRUE }, /* UNCOLLECTABLE */ { &GC_uobjfreelist[0], 0, - 0 | DS_LENGTH, TRUE /* add length to descr */, TRUE }, + 0 | GC_DS_LENGTH, TRUE /* add length to descr */, TRUE }, # ifdef ATOMIC_UNCOLLECTABLE /* AUNCOLLECTABLE */ { &GC_auobjfreelist[0], 0, - 0 | DS_LENGTH, FALSE /* add length to descr */, FALSE }, + 0 | GC_DS_LENGTH, FALSE /* add length to descr */, FALSE }, # endif # ifdef STUBBORN_ALLOC /*STUBBORN*/ { &GC_sobjfreelist[0], 0, - 0 | DS_LENGTH, TRUE /* add length to descr */, TRUE }, + 0 | GC_DS_LENGTH, TRUE /* add length to descr */, TRUE }, # endif }; @@ -105,6 +100,8 @@ word GC_n_rescuing_pages; /* Number of dirty pages we marked from */ mse * GC_mark_stack; +mse * GC_mark_stack_limit; + word GC_mark_stack_size = 0; #ifdef PARALLEL_MARK @@ -244,9 +241,7 @@ void GC_initiate_gc() if (GC_dirty_maintained) GC_check_dirty(); } # endif -# ifdef GATHERSTATS - GC_n_rescuing_pages = 0; -# endif + GC_n_rescuing_pages = 0; if (GC_mark_state == MS_NONE) { GC_mark_state = MS_PUSH_RESCUERS; } else if (GC_mark_state != MS_INVALID) { @@ -286,8 +281,7 @@ ptr_t cold_gc_frame; case MS_PUSH_RESCUERS: if (GC_mark_stack_top - >= GC_mark_stack + GC_mark_stack_size - - INITIAL_MARK_STACK_SIZE/2) { + >= GC_mark_stack_limit - INITIAL_MARK_STACK_SIZE/2) { /* Go ahead and mark, even though that might cause us to */ /* see more marked dirty objects later on. Avoid this */ /* in the future. */ @@ -297,9 +291,11 @@ ptr_t cold_gc_frame; } else { scan_ptr = GC_push_next_marked_dirty(scan_ptr); if (scan_ptr == 0) { -# ifdef PRINTSTATS +# ifdef CONDPRINT + if (GC_print_stats) { GC_printf1("Marked from %lu dirty pages\n", (unsigned long)GC_n_rescuing_pages); + } # endif GC_push_roots(FALSE, cold_gc_frame); GC_objects_are_marked = TRUE; @@ -402,10 +398,12 @@ ptr_t cold_gc_frame; #ifdef MSWIN32 } __except (GetExceptionCode() == EXCEPTION_ACCESS_VIOLATION ? EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH) { -# ifdef PRINTSTATS +# ifdef CONDPRINT + if (GC_print_stats) { GC_printf0("Caught ACCESS_VIOLATION in marker. " "Memory mapping disappeared.\n"); -# endif /* PRINTSTATS */ + } +# endif /* CONDPRINT */ /* We have bad roots on the stack. Discard mark stack. */ /* Rescan from marked objects. Redetermine roots. */ GC_invalidate_mark_state(); @@ -429,27 +427,28 @@ GC_bool GC_mark_stack_empty() #endif /* Given a pointer to someplace other than a small object page or the */ -/* first page of a large object, return a pointer either to the */ -/* start of the large object or NIL. */ -/* In the latter case black list the address current. */ -/* Returns NIL without black listing if current points to a block */ -/* with IGNORE_OFF_PAGE set. */ +/* first page of a large object, either: */ +/* - return a pointer to somewhere in the first page of the large */ +/* object, if current points to a large object. */ +/* In this case *hhdr is replaced with a pointer to the header */ +/* for the large object. */ +/* - just return current if it does not point to a large object. */ /*ARGSUSED*/ # ifdef PRINT_BLACK_LIST - ptr_t GC_find_start(current, hhdr, source) - word source; + ptr_t GC_find_start(current, hhdr, new_hdr_p, source) + ptr_t source; # else - ptr_t GC_find_start(current, hhdr) + ptr_t GC_find_start(current, hhdr, new_hdr_p) # define source 0 # endif register ptr_t current; -register hdr * hhdr; +register hdr *hhdr, **new_hdr_p; { -# ifdef ALL_INTERIOR_POINTERS + if (GC_all_interior_pointers) { if (hhdr != 0) { register ptr_t orig = current; - current = (ptr_t)HBLKPTR(current) + HDR_BYTES; + current = (ptr_t)HBLKPTR(current); do { current = current - HBLKSIZE*(word)hhdr; hhdr = HDR(current); @@ -459,18 +458,16 @@ register hdr * hhdr; if ((word *)orig - (word *)current >= (ptrdiff_t)(hhdr->hb_sz)) { /* Pointer past the end of the block */ - GC_ADD_TO_BLACK_LIST_NORMAL((word)orig, source); - return(0); + return(orig); } + *new_hdr_p = hhdr; return(current); } else { - GC_ADD_TO_BLACK_LIST_NORMAL((word)current, source); - return(0); + return(current); } -# else - GC_ADD_TO_BLACK_LIST_NORMAL((word)current, source); - return(0); -# endif + } else { + return(current); + } # undef source } @@ -485,9 +482,11 @@ mse * msp; { GC_mark_state = MS_INVALID; GC_mark_stack_too_small = TRUE; -# ifdef PRINTSTATS +# ifdef CONDPRINT + if (GC_print_stats) { GC_printf1("Mark stack overflow; current size = %lu entries\n", GC_mark_stack_size); + } # endif return(msp - GC_MARK_STACK_DISCARDS); } @@ -539,11 +538,11 @@ mse * mark_stack_limit; /* The following is 0 only for small objects described by a simple */ /* length descriptor. For many applications this is the common */ /* case, so we try to detect it quickly. */ - if (descr & ((~(WORDS_TO_BYTES(SPLIT_RANGE_WORDS) - 1)) | DS_TAGS)) { - word tag = descr & DS_TAGS; + if (descr & ((~(WORDS_TO_BYTES(SPLIT_RANGE_WORDS) - 1)) | GC_DS_TAGS)) { + word tag = descr & GC_DS_TAGS; switch(tag) { - case DS_LENGTH: + case GC_DS_LENGTH: /* Large length. */ /* Process part of the range to avoid pushing too much on the */ /* stack. */ @@ -572,9 +571,9 @@ mse * mark_stack_limit; /* considered. */ limit = (word *)((char *)limit + sizeof(word) - ALIGNMENT); break; - case DS_BITMAP: + case GC_DS_BITMAP: mark_stack_top--; - descr &= ~DS_TAGS; + descr &= ~GC_DS_TAGS; credit -= WORDS_TO_BYTES(WORDSZ/2); /* guess */ while (descr != 0) { if ((signed_word)descr < 0) { @@ -589,18 +588,18 @@ mse * mark_stack_limit; ++ current_p; } continue; - case DS_PROC: + case GC_DS_PROC: mark_stack_top--; - credit -= PROC_BYTES; + credit -= GC_PROC_BYTES; mark_stack_top = (*PROC(descr)) (current_p, mark_stack_top, mark_stack_limit, ENV(descr)); continue; - case DS_PER_OBJECT: + case GC_DS_PER_OBJECT: if ((signed_word)descr >= 0) { /* Descriptor is in the object. */ - descr = *(word *)((ptr_t)current_p + descr - DS_PER_OBJECT); + descr = *(word *)((ptr_t)current_p + descr - GC_DS_PER_OBJECT); } else { /* Descriptor is in type descriptor pointed to by first */ /* word in object. */ @@ -618,7 +617,8 @@ mse * mark_stack_limit; continue; } descr = *(word *)(type_descr - - (descr - (DS_PER_OBJECT - INDIR_PER_OBJ_BIAS))); + - (descr - (GC_DS_PER_OBJECT + - GC_INDIR_PER_OBJ_BIAS))); } if (0 == descr) { /* Can happen either because we generated a 0 descriptor */ @@ -734,7 +734,7 @@ mse * GC_steal_mark_stack(mse * low, mse * high, mse * local, ++top; top -> mse_descr = descr; top -> mse_start = p -> mse_start; - GC_ASSERT( top -> mse_descr & DS_TAGS != DS_LENGTH || + GC_ASSERT( top -> mse_descr & GC_DS_TAGS != GC_DS_LENGTH || top -> mse_descr < GC_greatest_plausible_heap_addr - GC_least_plausible_heap_addr); /* There is no synchronization here. We assume that at */ @@ -745,7 +745,7 @@ mse * GC_steal_mark_stack(mse * low, mse * high, mse * local, /* If this is a big object, count it as */ /* size/256 + 1 objects. */ ++i; - if ((descr & DS_TAGS) == DS_LENGTH) i += (descr >> 8); + if ((descr & GC_DS_TAGS) == GC_DS_LENGTH) i += (descr >> 8); } } *next = p; @@ -766,8 +766,10 @@ void GC_return_mark_stack(mse * low, mse * high) my_top = GC_mark_stack_top; my_start = my_top + 1; if (my_start - GC_mark_stack + stack_size > GC_mark_stack_size) { -# ifdef PRINTSTATS - GC_printf0("No room to copy back mark stack."); +# ifdef CONDPRINT + if (GC_print_stats) { + GC_printf0("No room to copy back mark stack."); + } # endif GC_mark_state = MS_INVALID; GC_mark_stack_too_small = TRUE; @@ -775,7 +777,10 @@ void GC_return_mark_stack(mse * low, mse * high) } else { BCOPY(low, my_start, stack_size * sizeof(mse)); GC_ASSERT(GC_mark_stack_top = my_top); - GC_memory_barrier(); +# if !defined(IA64) && !defined(HP_PA) + GC_memory_write_barrier(); +# endif + /* On IA64, the volatile write acts as a release barrier. */ GC_mark_stack_top = my_top + stack_size; } GC_release_mark_lock(); @@ -888,7 +893,7 @@ void GC_mark_local(mse *local_mark_stack, int id) if (0 == GC_active_count) GC_notify_all_marker(); while (GC_active_count > 0 && GC_first_nonempty > GC_mark_stack_top) { - /* We will be notofied if either GC_active_count */ + /* We will be notified if either GC_active_count */ /* reaches zero, or if more objects are pushed on */ /* the global mark stack. */ GC_wait_marker(); @@ -1009,13 +1014,13 @@ void GC_help_marker(word my_mark_no) static void alloc_mark_stack(n) word n; { - mse * new_stack = (mse *)GC_scratch_alloc(n * sizeof(struct ms_entry)); + mse * new_stack = (mse *)GC_scratch_alloc(n * sizeof(struct GC_ms_entry)); GC_mark_stack_too_small = FALSE; if (GC_mark_stack_size != 0) { if (new_stack != 0) { word displ = (word)GC_mark_stack & (GC_page_size - 1); - signed_word size = GC_mark_stack_size * sizeof(struct ms_entry); + signed_word size = GC_mark_stack_size * sizeof(struct GC_ms_entry); /* Recycle old space */ if (0 != displ) displ = GC_page_size - displ; @@ -1026,14 +1031,19 @@ word n; } GC_mark_stack = new_stack; GC_mark_stack_size = n; -# ifdef PRINTSTATS + GC_mark_stack_limit = new_stack + n; +# ifdef CONDPRINT + if (GC_print_stats) { GC_printf1("Grew mark stack to %lu frames\n", (unsigned long) GC_mark_stack_size); + } # endif } else { -# ifdef PRINTSTATS +# ifdef CONDPRINT + if (GC_print_stats) { GC_printf1("Failed to grow mark stack to %lu frames\n", (unsigned long) n); + } # endif } } else { @@ -1043,6 +1053,7 @@ word n; } GC_mark_stack = new_stack; GC_mark_stack_size = n; + GC_mark_stack_limit = new_stack + n; } GC_mark_stack_top = GC_mark_stack-1; } @@ -1069,13 +1080,13 @@ ptr_t top; top = (ptr_t)(((word) top) & ~(ALIGNMENT-1)); if (top == 0 || bottom == top) return; GC_mark_stack_top++; - if (GC_mark_stack_top >= GC_mark_stack + GC_mark_stack_size) { + if (GC_mark_stack_top >= GC_mark_stack_limit) { ABORT("unexpected mark stack overflow"); } length = top - bottom; -# if DS_TAGS > ALIGNMENT - 1 - length += DS_TAGS; - length &= ~DS_TAGS; +# if GC_DS_TAGS > ALIGNMENT - 1 + length += GC_DS_TAGS; + length &= ~GC_DS_TAGS; # endif GC_mark_stack_top -> mse_start = (word *)bottom; GC_mark_stack_top -> mse_descr = length; @@ -1131,7 +1142,7 @@ void (*push_fn) GC_PROTO((ptr_t bottom, ptr_t top)); (*push_fn)((ptr_t)h, top); } } - if (GC_mark_stack_top >= GC_mark_stack + GC_mark_stack_size) { + if (GC_mark_stack_top >= GC_mark_stack_limit) { ABORT("unexpected mark stack overflow"); } } @@ -1180,22 +1191,39 @@ word p; GC_PUSH_ONE_STACK(p, MARKED_FROM_REGISTER); } +struct GC_ms_entry *GC_mark_and_push(obj, mark_stack_ptr, mark_stack_limit, src) +GC_PTR obj; +struct GC_ms_entry * mark_stack_ptr; +struct GC_ms_entry * mark_stack_limit; +GC_PTR *src; +{ + PREFETCH(obj); + PUSH_CONTENTS(obj, mark_stack_ptr /* modified */, mark_stack_limit, src, + was_marked /* internally generated exit label */); + return mark_stack_ptr; +} + # ifdef __STDC__ # define BASE(p) (word)GC_base((void *)(p)) # else # define BASE(p) (word)GC_base((char *)(p)) # endif -/* As above, but argument passed preliminary test. */ +/* Mark and push (i.e. gray) a single object p onto the main */ +/* mark stack. Consider p to be valid if it is an interior */ +/* pointer. */ +/* The object p has passed a preliminary pointer validity */ +/* test, but we do not definitely know whether it is valid. */ +/* Mark bits are NOT atomically updated. Thus this must be the */ +/* only thread setting them. */ # if defined(PRINT_BLACK_LIST) || defined(KEEP_BACK_PTRS) - void GC_push_one_checked(p, interior_ptrs, source) + void GC_mark_and_push_stack(p, source) ptr_t source; # else - void GC_push_one_checked(p, interior_ptrs) + void GC_mark_and_push_stack(p) # define source 0 # endif register word p; -register GC_bool interior_ptrs; { register word r; register hdr * hhdr; @@ -1203,31 +1231,25 @@ register GC_bool interior_ptrs; GET_HDR(p, hhdr); if (IS_FORWARDING_ADDR_OR_NIL(hhdr)) { - if (hhdr != 0 && interior_ptrs) { + if (hhdr != 0) { r = BASE(p); hhdr = HDR(r); displ = BYTES_TO_WORDS(HBLKDISPL(r)); - } else { - hhdr = 0; } } else { register map_entry_type map_entry; displ = HBLKDISPL(p); map_entry = MAP_ENTRY((hhdr -> hb_map), displ); - if (map_entry == OBJ_INVALID) { -# ifndef ALL_INTERIOR_POINTERS - if (interior_ptrs) { + if (map_entry >= MAX_OFFSET) { + if (map_entry == OFFSET_TOO_BIG || !GC_all_interior_pointers) { r = BASE(p); displ = BYTES_TO_WORDS(HBLKDISPL(r)); if (r == 0) hhdr = 0; - } else { + } else { + /* Offset invalid, but map reflects interior pointers */ hhdr = 0; - } -# else - /* map already reflects interior pointers */ - hhdr = 0; -# endif + } } else { displ = BYTES_TO_WORDS(displ); displ -= map_entry; @@ -1237,22 +1259,18 @@ register GC_bool interior_ptrs; /* If hhdr != 0 then r == GC_base(p), only we did it faster. */ /* displ is the word index within the block. */ if (hhdr == 0) { - if (interior_ptrs) { -# ifdef PRINT_BLACK_LIST - GC_add_to_black_list_stack(p, source); -# else - GC_add_to_black_list_stack(p); -# endif - } else { - GC_ADD_TO_BLACK_LIST_NORMAL(p, source); -# undef source /* In case we had to define it. */ - } +# ifdef PRINT_BLACK_LIST + GC_add_to_black_list_stack(p, source); +# else + GC_add_to_black_list_stack(p); +# endif +# undef source /* In case we had to define it. */ } else { if (!mark_bit_from_hdr(hhdr, displ)) { set_mark_bit_from_hdr(hhdr, displ); GC_STORE_BACK_PTR(source, (ptr_t)r); PUSH_OBJ((word *)r, hhdr, GC_mark_stack_top, - &(GC_mark_stack[GC_mark_stack_size])); + GC_mark_stack_limit); } } } @@ -1346,7 +1364,7 @@ ptr_t bottom; ptr_t top; ptr_t cold_gc_frame; { -# ifdef ALL_INTERIOR_POINTERS + if (GC_all_interior_pointers) { # define EAGER_BYTES 1024 /* Push the hot end of the stack eagerly, so that register values */ /* saved inside GC frames are marked before they disappear. */ @@ -1362,9 +1380,9 @@ ptr_t cold_gc_frame; GC_push_all_eager(cold_gc_frame, top); GC_push_all(bottom, cold_gc_frame + sizeof(ptr_t)); # endif /* STACK_GROWS_UP */ -# else + } else { GC_push_all_eager(bottom, top); -# endif + } # ifdef TRACE_BUF GC_add_trace_entry("GC_push_all_stack", bottom, top); # endif @@ -1375,11 +1393,11 @@ void GC_push_all_stack(bottom, top) ptr_t bottom; ptr_t top; { -# ifdef ALL_INTERIOR_POINTERS + if (GC_all_interior_pointers) { GC_push_all(bottom, top); -# else + } else { GC_push_all_eager(bottom, top); -# endif + } } #if !defined(SMALL_CONFIG) && !defined(USE_MARK_BYTES) @@ -1389,7 +1407,7 @@ void GC_push_marked1(h, hhdr) struct hblk *h; register hdr * hhdr; { - word * mark_word_addr = &(hhdr->hb_marks[divWORDSZ(HDR_WORDS)]); + word * mark_word_addr = &(hhdr->hb_marks[0]); register word *p; word *plim; register int i; @@ -1397,6 +1415,10 @@ register hdr * hhdr; register word mark_word; register ptr_t greatest_ha = GC_greatest_plausible_heap_addr; register ptr_t least_ha = GC_least_plausible_heap_addr; + register mse * mark_stack_top = GC_mark_stack_top; + register mse * mark_stack_limit = GC_mark_stack_limit; +# define GC_mark_stack_top mark_stack_top +# define GC_mark_stack_limit mark_stack_limit # define GC_greatest_plausible_heap_addr greatest_ha # define GC_least_plausible_heap_addr least_ha @@ -1419,6 +1441,9 @@ register hdr * hhdr; } # undef GC_greatest_plausible_heap_addr # undef GC_least_plausible_heap_addr +# undef GC_mark_stack_top +# undef GC_mark_stack_limit + GC_mark_stack_top = mark_stack_top; } @@ -1430,7 +1455,7 @@ void GC_push_marked2(h, hhdr) struct hblk *h; register hdr * hhdr; { - word * mark_word_addr = &(hhdr->hb_marks[divWORDSZ(HDR_WORDS)]); + word * mark_word_addr = &(hhdr->hb_marks[0]); register word *p; word *plim; register int i; @@ -1438,6 +1463,10 @@ register hdr * hhdr; register word mark_word; register ptr_t greatest_ha = GC_greatest_plausible_heap_addr; register ptr_t least_ha = GC_least_plausible_heap_addr; + register mse * mark_stack_top = GC_mark_stack_top; + register mse * mark_stack_limit = GC_mark_stack_limit; +# define GC_mark_stack_top mark_stack_top +# define GC_mark_stack_limit mark_stack_limit # define GC_greatest_plausible_heap_addr greatest_ha # define GC_least_plausible_heap_addr least_ha @@ -1462,6 +1491,9 @@ register hdr * hhdr; } # undef GC_greatest_plausible_heap_addr # undef GC_least_plausible_heap_addr +# undef GC_mark_stack_top +# undef GC_mark_stack_limit + GC_mark_stack_top = mark_stack_top; } /* Push all objects reachable from marked objects in the given block */ @@ -1472,7 +1504,7 @@ void GC_push_marked4(h, hhdr) struct hblk *h; register hdr * hhdr; { - word * mark_word_addr = &(hhdr->hb_marks[divWORDSZ(HDR_WORDS)]); + word * mark_word_addr = &(hhdr->hb_marks[0]); register word *p; word *plim; register int i; @@ -1480,6 +1512,10 @@ register hdr * hhdr; register word mark_word; register ptr_t greatest_ha = GC_greatest_plausible_heap_addr; register ptr_t least_ha = GC_least_plausible_heap_addr; + register mse * mark_stack_top = GC_mark_stack_top; + register mse * mark_stack_limit = GC_mark_stack_limit; +# define GC_mark_stack_top mark_stack_top +# define GC_mark_stack_limit mark_stack_limit # define GC_greatest_plausible_heap_addr greatest_ha # define GC_least_plausible_heap_addr least_ha @@ -1508,6 +1544,9 @@ register hdr * hhdr; } # undef GC_greatest_plausible_heap_addr # undef GC_least_plausible_heap_addr +# undef GC_mark_stack_top +# undef GC_mark_stack_limit + GC_mark_stack_top = mark_stack_top; } #endif /* UNALIGNED */ @@ -1525,17 +1564,15 @@ register hdr * hhdr; register int word_no; register word * lim; register mse * GC_mark_stack_top_reg; - register mse * mark_stack_limit = &(GC_mark_stack[GC_mark_stack_size]); + register mse * mark_stack_limit = GC_mark_stack_limit; /* Some quick shortcuts: */ - if ((0 | DS_LENGTH) == descr) return; + if ((0 | GC_DS_LENGTH) == descr) return; if (GC_block_empty(hhdr)/* nothing marked */) return; -# ifdef GATHERSTATS - GC_n_rescuing_pages++; -# endif + GC_n_rescuing_pages++; GC_objects_are_marked = TRUE; if (sz > MAXOBJSZ) { - lim = (word *)h + HDR_WORDS; + lim = (word *)h; } else { lim = (word *)(h + 1) - sz; } @@ -1557,8 +1594,7 @@ register hdr * hhdr; # endif default: GC_mark_stack_top_reg = GC_mark_stack_top; - for (p = (word *)h + HDR_WORDS, word_no = HDR_WORDS; p <= lim; - p += sz, word_no += sz) { + for (p = (word *)h, word_no = 0; p <= lim; p += sz, word_no += sz) { if (mark_bit_from_hdr(hhdr, word_no)) { /* Mark from fields inside the object */ PUSH_OBJ((word *)p, hhdr, GC_mark_stack_top_reg, mark_stack_limit); @@ -1585,7 +1621,6 @@ register hdr * hhdr; return(GC_page_was_dirty(h)); } else { register ptr_t p = (ptr_t)h; - sz += HDR_WORDS; sz = WORDS_TO_BYTES(sz); while (p < (ptr_t)h + sz) { if (GC_page_was_dirty((struct hblk *)p)) return(TRUE); |