X-Git-Url: http://git.sourceforge.jp/view?a=blobdiff_plain;f=boehm-gc%2Fmark_rts.c;h=94eb0ddb37f3e81f70260e9361e67f517cce81f7;hb=6c07e6d85d043ec173479ec0096fabb8832a4299;hp=0e84f2732fc414039d73154fac36269550c98ba3;hpb=9bc8642e1f366a35c305b9abe9e01bf934b584b9;p=pf3gnuchains%2Fgcc-fork.git diff --git a/boehm-gc/mark_rts.c b/boehm-gc/mark_rts.c index 0e84f2732fc..94eb0ddb37f 100644 --- a/boehm-gc/mark_rts.c +++ b/boehm-gc/mark_rts.c @@ -11,9 +11,8 @@ * provided the above notices are retained, and a notice that the code was * modified is included with the above copyright notice. */ -/* Boehm, October 9, 1995 1:06 pm PDT */ # include -# include "gc_priv.h" +# include "private/gc_priv.h" /* Data structure for list of root sets. */ /* We keep a hash table, so that we can filter out duplicate additions. */ @@ -23,7 +22,7 @@ struct roots { ptr_t r_start; ptr_t r_end; - # ifndef MSWIN32 + # if !defined(MSWIN32) && !defined(MSWINCE) && !defined(CYGWIN32) struct roots * r_next; # endif GC_bool r_tmp; @@ -33,6 +32,8 @@ struct roots { struct roots GC_static_roots[MAX_ROOT_SETS]; */ +int GC_no_dls = 0; /* Register dynamic library data segments. */ + static int n_root_sets = 0; /* GC_static_roots[0..n_root_sets) contains the valid root sets. */ @@ -69,11 +70,12 @@ void GC_print_static_roots() GC_bool GC_is_static_root(p) ptr_t p; { - static int last_root_set = 0; + static int last_root_set = MAX_ROOT_SETS; register int i; - if (p >= GC_static_roots[last_root_set].r_start + if (last_root_set < n_root_sets + && p >= GC_static_roots[last_root_set].r_start && p < GC_static_roots[last_root_set].r_end) return(TRUE); for (i = 0; i < n_root_sets; i++) { if (p >= GC_static_roots[i].r_start @@ -85,7 +87,7 @@ ptr_t p; return(FALSE); } -#ifndef MSWIN32 +#if !defined(MSWIN32) && !defined(MSWINCE) && !defined(CYGWIN32) /* # define LOG_RT_SIZE 6 # define RT_SIZE (1 << LOG_RT_SIZE) -- Power of 2, may be != MAX_ROOT_SETS @@ -137,7 +139,7 @@ struct roots *p; GC_root_index[h] = p; } -# else /* MSWIN32 */ +# else /* MSWIN32 || MSWINCE || CYGWIN32 */ # define add_roots_to_index(p) @@ -173,7 +175,7 @@ GC_bool tmp; { struct roots * old; -# ifdef MSWIN32 +# if defined(MSWIN32) || defined(MSWINCE) || defined(CYGWIN32) /* Spend the time to ensure that there are no overlapping */ /* or adjacent intervals. */ /* This could be done faster with e.g. a */ @@ -242,7 +244,7 @@ GC_bool tmp; GC_static_roots[n_root_sets].r_start = (ptr_t)b; GC_static_roots[n_root_sets].r_end = (ptr_t)e; GC_static_roots[n_root_sets].r_tmp = tmp; -# ifndef MSWIN32 +# if !defined(MSWIN32) && !defined(MSWINCE) && !defined(CYGWIN32) GC_static_roots[n_root_sets].r_next = 0; # endif add_roots_to_index(GC_static_roots + n_root_sets); @@ -250,15 +252,18 @@ GC_bool tmp; n_root_sets++; } +static GC_bool roots_were_cleared = FALSE; + void GC_clear_roots GC_PROTO((void)) { DCL_LOCK_STATE; DISABLE_SIGNALS(); LOCK(); + roots_were_cleared = TRUE; n_root_sets = 0; GC_root_size = 0; -# ifndef MSWIN32 +# if !defined(MSWIN32) && !defined(MSWINCE) && !defined(CYGWIN32) { register int i; @@ -270,39 +275,117 @@ void GC_clear_roots GC_PROTO((void)) } /* Internal use only; lock held. */ +static void GC_remove_root_at_pos(i) +int i; +{ + GC_root_size -= (GC_static_roots[i].r_end - GC_static_roots[i].r_start); + GC_static_roots[i].r_start = GC_static_roots[n_root_sets-1].r_start; + GC_static_roots[i].r_end = GC_static_roots[n_root_sets-1].r_end; + GC_static_roots[i].r_tmp = GC_static_roots[n_root_sets-1].r_tmp; + n_root_sets--; +} + +#if !defined(MSWIN32) && !defined(MSWINCE) && !defined(CYGWIN32) +static void GC_rebuild_root_index() +{ + register int i; + + for (i = 0; i < RT_SIZE; i++) GC_root_index[i] = 0; + for (i = 0; i < n_root_sets; i++) + add_roots_to_index(GC_static_roots + i); +} +#endif + +/* Internal use only; lock held. */ void GC_remove_tmp_roots() { register int i; for (i = 0; i < n_root_sets; ) { if (GC_static_roots[i].r_tmp) { - GC_root_size -= - (GC_static_roots[i].r_end - GC_static_roots[i].r_start); - GC_static_roots[i].r_start = GC_static_roots[n_root_sets-1].r_start; - GC_static_roots[i].r_end = GC_static_roots[n_root_sets-1].r_end; - GC_static_roots[i].r_tmp = GC_static_roots[n_root_sets-1].r_tmp; - n_root_sets--; + GC_remove_root_at_pos(i); } else { i++; - } } -# ifndef MSWIN32 - { - register int i; - - for (i = 0; i < RT_SIZE; i++) GC_root_index[i] = 0; - for (i = 0; i < n_root_sets; i++) - add_roots_to_index(GC_static_roots + i); } -# endif + #if !defined(MSWIN32) && !defined(MSWINCE) && !defined(CYGWIN32) + GC_rebuild_root_index(); + #endif +} + +#if !defined(MSWIN32) && !defined(MSWINCE) && !defined(CYGWIN32) +void GC_remove_roots(b, e) +char * b; char * e; +{ + DCL_LOCK_STATE; + DISABLE_SIGNALS(); + LOCK(); + GC_remove_roots_inner(b, e); + UNLOCK(); + ENABLE_SIGNALS(); } -ptr_t GC_approx_sp() +/* Should only be called when the lock is held */ +void GC_remove_roots_inner(b,e) +char * b; char * e; { - word dummy; + int i; + for (i = 0; i < n_root_sets; ) { + if (GC_static_roots[i].r_start >= (ptr_t)b && GC_static_roots[i].r_end <= (ptr_t)e) { + GC_remove_root_at_pos(i); + } else { + i++; + } + } + GC_rebuild_root_index(); +} +#endif /* !defined(MSWIN32) && !defined(MSWINCE) && !defined(CYGWIN32) */ + +#if defined(MSWIN32) || defined(_WIN32_WCE_EMULATION) || defined(CYGWIN32) +/* Workaround for the OS mapping and unmapping behind our back: */ +/* Is the address p in one of the temporary static root sections? */ +GC_bool GC_is_tmp_root(p) +ptr_t p; +{ + static int last_root_set = MAX_ROOT_SETS; + register int i; - return((ptr_t)(&dummy)); + if (last_root_set < n_root_sets + && p >= GC_static_roots[last_root_set].r_start + && p < GC_static_roots[last_root_set].r_end) + return GC_static_roots[last_root_set].r_tmp; + for (i = 0; i < n_root_sets; i++) { + if (p >= GC_static_roots[i].r_start + && p < GC_static_roots[i].r_end) { + last_root_set = i; + return GC_static_roots[i].r_tmp; + } + } + return(FALSE); +} +#endif /* MSWIN32 || _WIN32_WCE_EMULATION || defined(CYGWIN32) */ + +ptr_t GC_approx_sp() +{ + VOLATILE word dummy; + + dummy = 42; /* Force stack to grow if necessary. Otherwise the */ + /* later accesses might cause the kernel to think we're */ + /* doing something wrong. */ +# ifdef _MSC_VER +# pragma warning(disable:4172) +# endif +#ifdef __GNUC__ + /* Eliminate a warning from GCC about taking the address of a + local variable. */ + return __builtin_frame_address (0); +#else + return ((ptr_t)(&dummy)); +#endif /* __GNUC__ */ +# ifdef _MSC_VER +# pragma warning(default:4172) +# endif } /* @@ -412,9 +495,8 @@ ptr_t cold_gc_frame; if (0 == cold_gc_frame) return; # ifdef STACK_GROWS_DOWN GC_push_all_eager(GC_approx_sp(), cold_gc_frame); -# ifdef IA64 - --> fix this -# endif + /* For IA64, the register stack backing store is handled */ + /* in the thread-specific code. */ # else GC_push_all_eager( cold_gc_frame, GC_approx_sp() ); # endif @@ -433,15 +515,16 @@ ptr_t cold_gc_frame; /* Previously set to backing store pointer. */ ptr_t bsp = (ptr_t) GC_save_regs_ret_val; ptr_t cold_gc_bs_pointer; -# ifdef ALL_INTERIOR_POINTERS + if (GC_all_interior_pointers) { cold_gc_bs_pointer = bsp - 2048; if (cold_gc_bs_pointer < BACKING_STORE_BASE) { cold_gc_bs_pointer = BACKING_STORE_BASE; + } else { + GC_push_all_stack(BACKING_STORE_BASE, cold_gc_bs_pointer); } - GC_push_all(BACKING_STORE_BASE, cold_gc_bs_pointer); -# else + } else { cold_gc_bs_pointer = BACKING_STORE_BASE; -# endif + } GC_push_all_eager(cold_gc_bs_pointer, bsp); /* All values should be sufficiently aligned that we */ /* dont have to worry about the boundary. */ @@ -455,6 +538,34 @@ ptr_t cold_gc_frame; } /* + * Push GC internal roots. Only called if there is some reason to believe + * these would not otherwise get registered. + */ +void GC_push_gc_structures GC_PROTO((void)) +{ + GC_push_finalizer_structures(); + GC_push_stubborn_structures(); +# if defined(THREADS) + GC_push_thread_structures(); +# endif +} + +#ifdef THREAD_LOCAL_ALLOC + void GC_mark_thread_local_free_lists(); +#endif + +void GC_cond_register_dynamic_libraries() +{ +# if (defined(DYNAMIC_LOADING) || defined(MSWIN32) || defined(MSWINCE) \ + || defined(CYGWIN32) || defined(PCR)) && !defined(SRC_M3) + GC_remove_tmp_roots(); + if (!GC_no_dls) GC_register_dynamic_libraries(); +# else + GC_no_dls = TRUE; +# endif +} + +/* * Call the mark routines (GC_tl_push for a single pointer, GC_push_conditional * on groups of pointers) on every top level accessible pointer. * If all is FALSE, arrange to push only possibly altered values. @@ -467,28 +578,22 @@ void GC_push_roots(all, cold_gc_frame) GC_bool all; ptr_t cold_gc_frame; { - register int i; + int i; + int kind; /* - * push registers - i.e., call GC_push_one(r) for each - * register contents r. - */ -# ifdef USE_GENERIC_PUSH_REGS - GC_generic_push_regs(cold_gc_frame); -# else - GC_push_regs(); /* usually defined in machine_dep.c */ -# endif - - /* * Next push static data. This must happen early on, since it's * not robust against mark stack overflow. */ - /* Reregister dynamic libraries, in case one got added. */ -# if (defined(DYNAMIC_LOADING) || defined(MSWIN32) || defined(PCR)) \ - && !defined(SRC_M3) - GC_remove_tmp_roots(); - GC_register_dynamic_libraries(); + /* Reregister dynamic libraries, in case one got added. */ + /* There is some argument for doing this as late as possible, */ + /* especially on win32, where it can change asynchronously. */ + /* In those cases, we do it here. But on other platforms, it's */ + /* not safe with the world stopped, so we do it earlier. */ +# if !defined(REGISTER_LIBRARIES_EARLY) + GC_cond_register_dynamic_libraries(); # endif + /* Mark everything in static data areas */ for (i = 0; i < n_root_sets; i++) { GC_push_conditional_with_exclusions( @@ -496,17 +601,58 @@ ptr_t cold_gc_frame; GC_static_roots[i].r_end, all); } + /* Mark all free list header blocks, if those were allocated from */ + /* the garbage collected heap. This makes sure they don't */ + /* disappear if we are not marking from static data. It also */ + /* saves us the trouble of scanning them, and possibly that of */ + /* marking the freelists. */ + for (kind = 0; kind < GC_n_kinds; kind++) { + GC_PTR base = GC_base(GC_obj_kinds[kind].ok_freelist); + if (0 != base) { + GC_set_mark_bit(base); + } + } + + /* Mark from GC internal roots if those might otherwise have */ + /* been excluded. */ + if (GC_no_dls || roots_were_cleared) { + GC_push_gc_structures(); + } + + /* Mark thread local free lists, even if their mark */ + /* descriptor excludes the link field. */ + /* If the world is not stopped, this is unsafe. It is */ + /* also unnecessary, since we will do this again with the */ + /* world stopped. */ +# ifdef THREAD_LOCAL_ALLOC + if (GC_world_stopped) GC_mark_thread_local_free_lists(); +# endif + /* - * Now traverse stacks. + * Now traverse stacks, and mark from register contents. + * These must be done last, since they can legitimately overflow + * the mark stack. */ -# if !defined(USE_GENERIC_PUSH_REGS) +# ifdef USE_GENERIC_PUSH_REGS + GC_generic_push_regs(cold_gc_frame); + /* Also pushes stack, so that we catch callee-save registers */ + /* saved inside the GC_push_regs frame. */ +# else + /* + * push registers - i.e., call GC_push_one(r) for each + * register contents r. + */ + GC_push_regs(); /* usually defined in machine_dep.c */ GC_push_current_stack(cold_gc_frame); - /* IN the threads case, this only pushes collector frames. */ - /* In the USE_GENERIC_PUSH_REGS case, this is done inside */ - /* GC_push_regs, so that we catch callee-save registers saved */ - /* inside the GC_push_regs frame. */ + /* In the threads case, this only pushes collector frames. */ + /* In the case of linux threads on IA64, the hot section of */ + /* the main stack is marked here, but the register stack */ + /* backing store is handled in the threads-specific code. */ # endif if (GC_push_other_roots != 0) (*GC_push_other_roots)(); /* In the threads case, this also pushes thread stacks. */ + /* Note that without interior pointer recognition lots */ + /* of stuff may have been pushed already, and this */ + /* should be careful about mark stack overflows. */ }