version 1.1.1.1, 1999/12/03 07:39:10 |
version 1.6, 2002/07/24 08:00:10 |
|
|
* provided the above notices are retained, and a notice that the code was |
* provided the above notices are retained, and a notice that the code was |
* modified is included with the above copyright notice. |
* modified is included with the above copyright notice. |
*/ |
*/ |
/* Boehm, October 9, 1995 1:06 pm PDT */ |
|
# include <stdio.h> |
# include <stdio.h> |
# include "gc_priv.h" |
# include "private/gc_priv.h" |
|
|
/* Data structure for list of root sets. */ |
/* Data structure for list of root sets. */ |
/* We keep a hash table, so that we can filter out duplicate additions. */ |
/* We keep a hash table, so that we can filter out duplicate additions. */ |
|
|
struct roots { |
struct roots { |
ptr_t r_start; |
ptr_t r_start; |
ptr_t r_end; |
ptr_t r_end; |
# ifndef MSWIN32 |
# if !defined(MSWIN32) && !defined(MSWINCE) |
struct roots * r_next; |
struct roots * r_next; |
# endif |
# endif |
GC_bool r_tmp; |
GC_bool r_tmp; |
|
|
struct roots GC_static_roots[MAX_ROOT_SETS]; |
struct roots GC_static_roots[MAX_ROOT_SETS]; |
*/ |
*/ |
|
|
|
int GC_no_dls = 0; /* Register dynamic library data segments. */ |
|
|
static int n_root_sets = 0; |
static int n_root_sets = 0; |
|
|
/* GC_static_roots[0..n_root_sets) contains the valid root sets. */ |
/* GC_static_roots[0..n_root_sets) contains the valid root sets. */ |
Line 69 void GC_print_static_roots() |
|
Line 70 void GC_print_static_roots() |
|
GC_bool GC_is_static_root(p) |
GC_bool GC_is_static_root(p) |
ptr_t p; |
ptr_t p; |
{ |
{ |
static int last_root_set = 0; |
static int last_root_set = MAX_ROOT_SETS; |
register int i; |
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); |
&& p < GC_static_roots[last_root_set].r_end) return(TRUE); |
for (i = 0; i < n_root_sets; i++) { |
for (i = 0; i < n_root_sets; i++) { |
if (p >= GC_static_roots[i].r_start |
if (p >= GC_static_roots[i].r_start |
|
|
return(FALSE); |
return(FALSE); |
} |
} |
|
|
#ifndef MSWIN32 |
#if !defined(MSWIN32) && !defined(MSWINCE) |
/* |
/* |
# define LOG_RT_SIZE 6 |
# define LOG_RT_SIZE 6 |
# define RT_SIZE (1 << LOG_RT_SIZE) -- Power of 2, may be != MAX_ROOT_SETS |
# define RT_SIZE (1 << LOG_RT_SIZE) -- Power of 2, may be != MAX_ROOT_SETS |
Line 137 struct roots *p; |
|
Line 139 struct roots *p; |
|
GC_root_index[h] = p; |
GC_root_index[h] = p; |
} |
} |
|
|
# else /* MSWIN32 */ |
# else /* MSWIN32 || MSWINCE */ |
|
|
# define add_roots_to_index(p) |
# define add_roots_to_index(p) |
|
|
|
|
{ |
{ |
struct roots * old; |
struct roots * old; |
|
|
# ifdef MSWIN32 |
# if defined(MSWIN32) || defined(MSWINCE) |
/* Spend the time to ensure that there are no overlapping */ |
/* Spend the time to ensure that there are no overlapping */ |
/* or adjacent intervals. */ |
/* or adjacent intervals. */ |
/* This could be done faster with e.g. a */ |
/* This could be done faster with e.g. a */ |
|
|
GC_static_roots[n_root_sets].r_start = (ptr_t)b; |
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_end = (ptr_t)e; |
GC_static_roots[n_root_sets].r_tmp = tmp; |
GC_static_roots[n_root_sets].r_tmp = tmp; |
# ifndef MSWIN32 |
# if !defined(MSWIN32) && !defined(MSWINCE) |
GC_static_roots[n_root_sets].r_next = 0; |
GC_static_roots[n_root_sets].r_next = 0; |
# endif |
# endif |
add_roots_to_index(GC_static_roots + n_root_sets); |
add_roots_to_index(GC_static_roots + n_root_sets); |
|
|
n_root_sets++; |
n_root_sets++; |
} |
} |
|
|
|
static GC_bool roots_were_cleared = FALSE; |
|
|
void GC_clear_roots GC_PROTO((void)) |
void GC_clear_roots GC_PROTO((void)) |
{ |
{ |
DCL_LOCK_STATE; |
DCL_LOCK_STATE; |
|
|
DISABLE_SIGNALS(); |
DISABLE_SIGNALS(); |
LOCK(); |
LOCK(); |
|
roots_were_cleared = TRUE; |
n_root_sets = 0; |
n_root_sets = 0; |
GC_root_size = 0; |
GC_root_size = 0; |
# ifndef MSWIN32 |
# if !defined(MSWIN32) && !defined(MSWINCE) |
{ |
{ |
register int i; |
register int i; |
|
|
Line 286 void GC_remove_tmp_roots() |
|
Line 291 void GC_remove_tmp_roots() |
|
i++; |
i++; |
} |
} |
} |
} |
# ifndef MSWIN32 |
# if !defined(MSWIN32) && !defined(MSWINCE) |
{ |
{ |
register int i; |
register int i; |
|
|
Line 298 void GC_remove_tmp_roots() |
|
Line 303 void GC_remove_tmp_roots() |
|
|
|
} |
} |
|
|
|
#if defined(MSWIN32) || defined(_WIN32_WCE_EMULATION) |
|
/* 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; |
|
|
|
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 */ |
|
|
ptr_t GC_approx_sp() |
ptr_t GC_approx_sp() |
{ |
{ |
word dummy; |
word dummy; |
|
|
|
# ifdef _MSC_VER |
|
# pragma warning(disable:4172) |
|
# endif |
return((ptr_t)(&dummy)); |
return((ptr_t)(&dummy)); |
|
# ifdef _MSC_VER |
|
# pragma warning(default:4172) |
|
# endif |
} |
} |
|
|
/* |
/* |
Line 412 ptr_t cold_gc_frame; |
|
Line 447 ptr_t cold_gc_frame; |
|
if (0 == cold_gc_frame) return; |
if (0 == cold_gc_frame) return; |
# ifdef STACK_GROWS_DOWN |
# ifdef STACK_GROWS_DOWN |
GC_push_all_eager(GC_approx_sp(), cold_gc_frame); |
GC_push_all_eager(GC_approx_sp(), cold_gc_frame); |
|
/* For IA64, the register stack backing store is handled */ |
|
/* in the thread-specific code. */ |
# else |
# else |
GC_push_all_eager( cold_gc_frame, GC_approx_sp() ); |
GC_push_all_eager( cold_gc_frame, GC_approx_sp() ); |
# endif |
# endif |
Line 419 ptr_t cold_gc_frame; |
|
Line 456 ptr_t cold_gc_frame; |
|
# ifdef STACK_GROWS_DOWN |
# ifdef STACK_GROWS_DOWN |
GC_push_all_stack_partially_eager( GC_approx_sp(), GC_stackbottom, |
GC_push_all_stack_partially_eager( GC_approx_sp(), GC_stackbottom, |
cold_gc_frame ); |
cold_gc_frame ); |
|
# ifdef IA64 |
|
/* We also need to push the register stack backing store. */ |
|
/* This should really be done in the same way as the */ |
|
/* regular stack. For now we fudge it a bit. */ |
|
/* Note that the backing store grows up, so we can't use */ |
|
/* GC_push_all_stack_partially_eager. */ |
|
{ |
|
extern word GC_save_regs_ret_val; |
|
/* Previously set to backing store pointer. */ |
|
ptr_t bsp = (ptr_t) GC_save_regs_ret_val; |
|
ptr_t cold_gc_bs_pointer; |
|
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); |
|
} |
|
} else { |
|
cold_gc_bs_pointer = BACKING_STORE_BASE; |
|
} |
|
GC_push_all_eager(cold_gc_bs_pointer, bsp); |
|
/* All values should be sufficiently aligned that we */ |
|
/* dont have to worry about the boundary. */ |
|
} |
|
# endif |
# else |
# else |
GC_push_all_stack_partially_eager( GC_stackbottom, GC_approx_sp(), |
GC_push_all_stack_partially_eager( GC_stackbottom, GC_approx_sp(), |
cold_gc_frame ); |
cold_gc_frame ); |
Line 427 ptr_t cold_gc_frame; |
|
Line 490 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 |
|
|
|
/* |
* Call the mark routines (GC_tl_push for a single pointer, GC_push_conditional |
* Call the mark routines (GC_tl_push for a single pointer, GC_push_conditional |
* on groups of pointers) on every top level accessible pointer. |
* on groups of pointers) on every top level accessible pointer. |
* If all is FALSE, arrange to push only possibly altered values. |
* If all is FALSE, arrange to push only possibly altered values. |
Line 442 ptr_t cold_gc_frame; |
|
Line 522 ptr_t cold_gc_frame; |
|
register int i; |
register int i; |
|
|
/* |
/* |
* 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 |
* Next push static data. This must happen early on, since it's |
* not robust against mark stack overflow. |
* not robust against mark stack overflow. |
*/ |
*/ |
/* Reregister dynamic libraries, in case one got added. */ |
/* Reregister dynamic libraries, in case one got added. */ |
# if (defined(DYNAMIC_LOADING) || defined(MSWIN32) || defined(PCR)) \ |
# if (defined(DYNAMIC_LOADING) || defined(MSWIN32) || defined(MSWINCE) \ |
&& !defined(SRC_M3) |
|| defined(PCR)) && !defined(SRC_M3) |
GC_remove_tmp_roots(); |
GC_remove_tmp_roots(); |
GC_register_dynamic_libraries(); |
if (!GC_no_dls) GC_register_dynamic_libraries(); |
|
# else |
|
GC_no_dls = TRUE; |
# endif |
# endif |
|
|
/* Mark everything in static data areas */ |
/* Mark everything in static data areas */ |
for (i = 0; i < n_root_sets; i++) { |
for (i = 0; i < n_root_sets; i++) { |
GC_push_conditional_with_exclusions( |
GC_push_conditional_with_exclusions( |
Line 468 ptr_t cold_gc_frame; |
|
Line 541 ptr_t cold_gc_frame; |
|
GC_static_roots[i].r_end, all); |
GC_static_roots[i].r_end, all); |
} |
} |
|
|
|
/* 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. */ |
|
# ifdef THREAD_LOCAL_ALLOC |
|
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); |
GC_push_current_stack(cold_gc_frame); |
/* IN the threads case, this only pushes collector frames. */ |
/* In the threads case, this only pushes collector frames. */ |
/* In the USE_GENERIC_PUSH_REGS case, this is done inside */ |
/* In the case of linux threads on IA64, the hot section of */ |
/* GC_push_regs, so that we catch callee-save registers saved */ |
/* the main stack is marked here, but the register stack */ |
/* inside the GC_push_regs frame. */ |
/* backing store is handled in the threads-specific code. */ |
# endif |
# endif |
if (GC_push_other_roots != 0) (*GC_push_other_roots)(); |
if (GC_push_other_roots != 0) (*GC_push_other_roots)(); |
/* In the threads case, this also pushes thread stacks. */ |
/* 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. */ |
} |
} |
|
|