diff options
author | Ivan Maidanski <ivmai@mail.ru> | 2011-07-26 17:28:12 +0400 |
---|---|---|
committer | Ivan Maidanski <ivmai@mail.ru> | 2011-07-26 17:28:12 +0400 |
commit | 111a44f98adde07d205c92656ad9b935ca2a39a8 (patch) | |
tree | 8a0cb4e60f636fd09dd0d2e1a3a7f3a4ac0a1bb0 /mark.c | |
parent | f3632431e72d48bc7772b0752e29bb1e2a0901c6 (diff) | |
download | bdwgc-111a44f98adde07d205c92656ad9b935ca2a39a8.tar.gz |
gc6.2 tarball importgc6_2
Diffstat (limited to 'mark.c')
-rw-r--r-- | mark.c | 180 |
1 files changed, 148 insertions, 32 deletions
@@ -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() @@ -571,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, @@ -645,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); @@ -654,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); @@ -668,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 */ @@ -1346,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; @@ -1370,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. */ @@ -1379,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); @@ -1399,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); |