summaryrefslogtreecommitdiff
path: root/mark.c
diff options
context:
space:
mode:
Diffstat (limited to 'mark.c')
-rw-r--r--mark.c180
1 files changed, 148 insertions, 32 deletions
diff --git a/mark.c b/mark.c
index 8ca36f1..ca94729 100644
--- a/mark.c
+++ b/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()
@@ -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);