diff options
author | jsturm <jsturm@138bc75d-0d04-0410-961f-82ee72b054a4> | 2003-07-28 04:18:23 +0000 |
---|---|---|
committer | jsturm <jsturm@138bc75d-0d04-0410-961f-82ee72b054a4> | 2003-07-28 04:18:23 +0000 |
commit | 341281013a7334da0896c950d9c254e42692c479 (patch) | |
tree | 827bf34dcb0c2786d314e5fa136528e5a4feb6f7 /boehm-gc/mark.c | |
parent | 975f1a7b2a8b2194905616d3fb05653329a2afce (diff) | |
download | gcc-341281013a7334da0896c950d9c254e42692c479.tar.gz |
Import GC 6.3alpha1.
* BCC_MAKEFILE: Merge with GC 6.3alpha1 release.
* ChangeLog: Likewise.
* Makefile.am: Likewise.
* Makefile.direct: Likewise.
* Makefile.dj: Likewise.
* allchblk.c: Likewise.
* alloc.c: Likewise.
* backgraph.c: Likewise.
* configure.host: Likewise.
* configure.in: Likewise.
* dbg_mlc.c: Likewise.
* dyn_load.c: Likewise.
* finalize.c: Likewise.
* gc_cpp.cc: Likewise.
* gc_dlopen.c: Likewise.
* gcj_mlc.c: Likewise.
* if_mach.c: Likewise.
* mach_dep.c: Likewise.
* malloc.c: Likewise.
* mallocx.c: Likewise.
* mark.c: Likewise.
* mark_rts.c: Likewise.
* misc.c: Likewise.
* os_dep.c: Likewise.
* ptr_chck.c: Likewise.
* reclaim.c: Likewise.
* solaris_pthreads.c: Likewise.
* solaris_threads.c: Likewise.
* sparc_mach_dep.S: Likewise.
* threadlibs.c: Likewise.
* typd_mlc.c: Likewise.
* version.h: Likewise.
* win32_threads.c: Likewise.
* Mac_files/MacOS_Test_config.h: Likewise.
* Mac_files/MacOS_config.h: Likewise.
* cord/cordbscs.c: Likewise.
* cord/cordprnt.c: Likewise.
* cord/de_win.c: Likewise.
* doc/README: Likewise.
* doc/README.MacOSX: Likewise.
* doc/README.changes: Likewise.
* doc/README.environment: Likewise.
* doc/README.ews4800: Likewise.
* doc/README.linux: Likewise.
* doc/README.macros: Likewise.
* doc/README.win32: Likewise.
* doc/debugging.html: Likewise.
* doc/gcdescr.html: Likewise.
* doc/tree.html: Likewise.
* include/Makefile.in: Likewise.
* include/gc.h: Likewise.
* include/gc_cpp.h: Likewise.
* include/gc_local_alloc.h: Likewise.
* include/gc_mark.h: Likewise.
* include/gc_pthread_redirects.h: Likewise.
* include/gc_typed.h: Likewise.
* include/new_gc_alloc.h: Likewise.
* include/private/dbg_mlc.h: Likewise.
* include/private/gc_hdrs.h: Likewise.
* include/private/gc_locks.h: Likewise.
* include/private/gc_pmark.h: Likewise.
* include/private/gc_priv.h: Likewise.
* include/private/gcconfig.h: Likewise.
* include/private/solaris_threads.h: Likewise.
* include/private/specific.h: Likewise.
* tests/test.c: Likewise.
* tests/test_cpp.cc: Likewise.
* configure: Rebuild.
* Makefile.in: Rebuild.
* mips_sgi_mach_dep.s: Add.
* alpha_mach_dep.s: Remove.
* irix_threads.c: Remove.
* linux_threads.c: Remove.
* mips_sgi_mach_dep.S: Remove.
* missing: Remove.
* powerpc_macosx_mach_dep.s: Remove.
* doc/Makefile.am: Remove.
* doc/Makefile.in: Remove.
git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@69880 138bc75d-0d04-0410-961f-82ee72b054a4
Diffstat (limited to 'boehm-gc/mark.c')
-rw-r--r-- | boehm-gc/mark.c | 216 |
1 files changed, 168 insertions, 48 deletions
diff --git a/boehm-gc/mark.c b/boehm-gc/mark.c index eb5b9eeb34d..ca947290291 100644 --- a/boehm-gc/mark.c +++ b/boehm-gc/mark.c @@ -19,6 +19,10 @@ # include <stdio.h> # include "private/gc_pmark.h" +#if defined(MSWIN32) && defined(__GNUC__) +# include <excpt.h> +#endif + /* We put this here to minimize the risk of inlining. */ /*VARARGS*/ #ifdef __WATCOMC__ @@ -261,20 +265,20 @@ static void alloc_mark_stack(); /* remains valid until all marking is complete. */ /* A zero value indicates that it's OK to miss some */ /* register values. */ -GC_bool GC_mark_some(cold_gc_frame) -ptr_t cold_gc_frame; +/* We hold the allocation lock. In the case of */ +/* incremental collection, the world may not be stopped.*/ +#ifdef MSWIN32 + /* For win32, this is called after we establish a structured */ + /* exception handler, in case Windows unmaps one of our root */ + /* segments. See below. In either case, we acquire the */ + /* allocator lock long before we get here. */ + GC_bool GC_mark_some_inner(cold_gc_frame) + ptr_t cold_gc_frame; +#else + GC_bool GC_mark_some(cold_gc_frame) + ptr_t cold_gc_frame; +#endif { -#if defined(MSWIN32) && !defined(__GNUC__) - /* Windows 98 appears to asynchronously create and remove writable */ - /* memory mappings, for reasons we haven't yet understood. Since */ - /* we look for writable regions to determine the root set, we may */ - /* try to mark from an address range that disappeared since we */ - /* started the collection. Thus we have to recover from faults here. */ - /* This code does not appear to be necessary for Windows 95/NT/2000. */ - /* Note that this code should never generate an incremental GC write */ - /* fault. */ - __try { -#endif /* defined(MSWIN32) && !defined(__GNUC__) */ switch(GC_mark_state) { case MS_NONE: return(FALSE); @@ -395,23 +399,130 @@ ptr_t cold_gc_frame; ABORT("GC_mark_some: bad state"); return(FALSE); } -#if defined(MSWIN32) && !defined(__GNUC__) - } __except (GetExceptionCode() == EXCEPTION_ACCESS_VIOLATION ? - EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH) { -# ifdef CONDPRINT - if (GC_print_stats) { - GC_printf0("Caught ACCESS_VIOLATION in marker. " - "Memory mapping disappeared.\n"); +} + + +#ifdef MSWIN32 + +# ifdef __GNUC__ + + typedef struct { + EXCEPTION_REGISTRATION ex_reg; + void *alt_path; + } ext_ex_regn; + + + static EXCEPTION_DISPOSITION mark_ex_handler( + struct _EXCEPTION_RECORD *ex_rec, + void *est_frame, + struct _CONTEXT *context, + void *disp_ctxt) + { + if (ex_rec->ExceptionCode == STATUS_ACCESS_VIOLATION) { + ext_ex_regn *xer = (ext_ex_regn *)est_frame; + + /* Unwind from the inner function assuming the standard */ + /* function prologue. */ + /* Assumes code has not been compiled with */ + /* -fomit-frame-pointer. */ + context->Esp = context->Ebp; + context->Ebp = *((DWORD *)context->Esp); + context->Esp = context->Esp - 8; + + /* Resume execution at the "real" handler within the */ + /* wrapper function. */ + context->Eip = (DWORD )(xer->alt_path); + + return ExceptionContinueExecution; + + } else { + return ExceptionContinueSearch; + } + } +# endif /* __GNUC__ */ + + + GC_bool GC_mark_some(cold_gc_frame) + ptr_t cold_gc_frame; + { + GC_bool ret_val; + +# ifndef __GNUC__ + /* Windows 98 appears to asynchronously create and remove */ + /* writable memory mappings, for reasons we haven't yet */ + /* understood. Since we look for writable regions to */ + /* determine the root set, we may try to mark from an */ + /* address range that disappeared since we started the */ + /* collection. Thus we have to recover from faults here. */ + /* This code does not appear to be necessary for Windows */ + /* 95/NT/2000. Note that this code should never generate */ + /* an incremental GC write fault. */ + + __try { + +# else /* __GNUC__ */ + + /* Manually install an exception handler since GCC does */ + /* not yet support Structured Exception Handling (SEH) on */ + /* Win32. */ + + ext_ex_regn er; + + er.alt_path = &&handle_ex; + er.ex_reg.handler = mark_ex_handler; + asm volatile ("movl %%fs:0, %0" : "=r" (er.ex_reg.prev)); + asm volatile ("movl %0, %%fs:0" : : "r" (&er)); + +# endif /* __GNUC__ */ + + ret_val = GC_mark_some_inner(cold_gc_frame); + +# ifndef __GNUC__ + + } __except (GetExceptionCode() == EXCEPTION_ACCESS_VIOLATION ? + EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH) { + +# else /* __GNUC__ */ + + /* Prevent GCC from considering the following code unreachable */ + /* and thus eliminating it. */ + if (er.alt_path != 0) + goto rm_handler; + +handle_ex: + /* Execution resumes from here on an access violation. */ + +# endif /* __GNUC__ */ + +# ifdef CONDPRINT + if (GC_print_stats) { + GC_printf0("Caught ACCESS_VIOLATION in marker. " + "Memory mapping disappeared.\n"); + } +# endif /* CONDPRINT */ + + /* We have bad roots on the stack. Discard mark stack. */ + /* Rescan from marked objects. Redetermine roots. */ + GC_invalidate_mark_state(); + scan_ptr = 0; + + ret_val = FALSE; + +# ifndef __GNUC__ + } -# endif /* CONDPRINT */ - /* We have bad roots on the stack. Discard mark stack. */ - /* Rescan from marked objects. Redetermine roots. */ - GC_invalidate_mark_state(); - scan_ptr = 0; - return FALSE; + +# else /* __GNUC__ */ + +rm_handler: + /* Uninstall the exception handler */ + asm volatile ("mov %0, %%fs:0" : : "r" (er.ex_reg.prev)); + +# endif /* __GNUC__ */ + + return ret_val; } -#endif /* defined(MSWIN32) && !defined(__GNUC__) */ -} +#endif /* MSWIN32 */ GC_bool GC_mark_stack_empty() @@ -434,13 +545,7 @@ GC_bool GC_mark_stack_empty() /* 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, new_hdr_p, source) - ptr_t source; -# else - ptr_t GC_find_start(current, hhdr, new_hdr_p) -# define source 0 -# endif +ptr_t GC_find_start(current, hhdr, new_hdr_p) register ptr_t current; register hdr *hhdr, **new_hdr_p; { @@ -468,7 +573,6 @@ register hdr *hhdr, **new_hdr_p; } else { return(current); } -# undef source } void GC_invalidate_mark_state() @@ -546,8 +650,8 @@ mse * mark_stack_limit; /* Large length. */ /* Process part of the range to avoid pushing too much on the */ /* stack. */ - GC_ASSERT(descr < GC_greatest_plausible_heap_addr - - GC_least_plausible_heap_addr); + GC_ASSERT(descr < (word)GC_greatest_plausible_heap_addr + - (word)GC_least_plausible_heap_addr); # ifdef PARALLEL_MARK # define SHARE_BYTES 2048 if (descr > SHARE_BYTES && GC_parallel @@ -578,6 +682,7 @@ mse * mark_stack_limit; while (descr != 0) { if ((signed_word)descr < 0) { current = *current_p; + FIXUP_POINTER(current); if ((ptr_t)current >= least_ha && (ptr_t)current < greatest_ha) { PREFETCH(current); HC_PUSH_CONTENTS((ptr_t)current, mark_stack_top, @@ -652,6 +757,7 @@ mse * mark_stack_limit; PREFETCH((ptr_t)limit - PREF_DIST*CACHE_LINE_SIZE); GC_ASSERT(limit >= current_p); deferred = *limit; + FIXUP_POINTER(deferred); limit = (word *)((char *)limit - ALIGNMENT); if ((ptr_t)deferred >= least_ha && (ptr_t)deferred < greatest_ha) { PREFETCH(deferred); @@ -661,6 +767,7 @@ mse * mark_stack_limit; /* Unroll once, so we don't do too many of the prefetches */ /* based on limit. */ deferred = *limit; + FIXUP_POINTER(deferred); limit = (word *)((char *)limit - ALIGNMENT); if ((ptr_t)deferred >= least_ha && (ptr_t)deferred < greatest_ha) { PREFETCH(deferred); @@ -675,6 +782,7 @@ mse * mark_stack_limit; /* Since HC_PUSH_CONTENTS expands to a lot of code, */ /* we don't. */ current = *current_p; + FIXUP_POINTER(current); PREFETCH((ptr_t)current_p + PREF_DIST*CACHE_LINE_SIZE); if ((ptr_t)current >= least_ha && (ptr_t)current < greatest_ha) { /* Prefetch the contents of the object we just pushed. It's */ @@ -726,22 +834,33 @@ mse * GC_steal_mark_stack(mse * low, mse * high, mse * local, mse *top = local - 1; unsigned i = 0; + /* Make sure that prior writes to the mark stack are visible. */ + /* On some architectures, the fact that the reads are */ + /* volatile should suffice. */ +# if !defined(IA64) && !defined(HP_PA) && !defined(I386) + GC_memory_barrier(); +# endif GC_ASSERT(high >= low-1 && high - low + 1 <= GC_mark_stack_size); for (p = low; p <= high && i <= max; ++p) { word descr = *(volatile word *) &(p -> mse_descr); + /* In the IA64 memory model, the following volatile store is */ + /* ordered after this read of descr. Thus a thread must read */ + /* the original nonzero value. HP_PA appears to be similar, */ + /* and if I'm reading the P4 spec correctly, X86 is probably */ + /* also OK. In some other cases we need a barrier. */ +# if !defined(IA64) && !defined(HP_PA) && !defined(I386) + GC_memory_barrier(); +# endif if (descr != 0) { *(volatile word *) &(p -> mse_descr) = 0; + /* More than one thread may get this entry, but that's only */ + /* a minor performance problem. */ ++top; top -> mse_descr = descr; top -> mse_start = p -> mse_start; 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 */ - /* least one thread will see the original descriptor. */ - /* Otherwise we need a barrier. */ - /* More than one thread may get this entry, but that's only */ - /* a minor performance problem. */ /* If this is a big object, count it as */ /* size/256 + 1 objects. */ ++i; @@ -778,7 +897,7 @@ void GC_return_mark_stack(mse * low, mse * high) BCOPY(low, my_start, stack_size * sizeof(mse)); GC_ASSERT(GC_mark_stack_top = my_top); # if !defined(IA64) && !defined(HP_PA) - GC_memory_write_barrier(); + GC_memory_barrier(); # endif /* On IA64, the volatile write acts as a release barrier. */ GC_mark_stack_top = my_top + stack_size; @@ -1342,8 +1461,8 @@ ptr_t top; # define GC_least_plausible_heap_addr least_ha if (top == 0) return; - /* check all pointers in range and put in push if they appear */ - /* to be valid. */ + /* check all pointers in range and push if they appear */ + /* to be valid. */ lim = t - 1 /* longword */; for (p = b; p <= lim; p = (word *)(((char *)p) + ALIGNMENT)) { q = *p; @@ -1366,7 +1485,7 @@ ptr_t bottom; ptr_t top; ptr_t cold_gc_frame; { - if (GC_all_interior_pointers) { + if (!NEED_FIXUP_POINTER && 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. */ @@ -1375,6 +1494,7 @@ ptr_t cold_gc_frame; GC_push_all_stack(bottom, top); return; } + GC_ASSERT(bottom <= cold_gc_frame && cold_gc_frame <= top); # ifdef STACK_GROWS_DOWN GC_push_all(cold_gc_frame - sizeof(ptr_t), top); GC_push_all_eager(bottom, cold_gc_frame); @@ -1395,7 +1515,7 @@ void GC_push_all_stack(bottom, top) ptr_t bottom; ptr_t top; { - if (GC_all_interior_pointers) { + if (!NEED_FIXUP_POINTER && GC_all_interior_pointers) { GC_push_all(bottom, top); } else { GC_push_all_eager(bottom, top); |