summaryrefslogtreecommitdiff
path: root/mark_rts.c
diff options
context:
space:
mode:
authorivmai <ivmai>2009-09-19 11:28:28 +0200
committerIvan Maidanski <ivmai@mail.ru>2011-07-26 19:06:47 +0200
commitd1d1fc8d9e51ffa49da97f99ad6158c090fb7e80 (patch)
tree8abfd8aadc9b834f34c25c779e7f7825edfd285a /mark_rts.c
parente3bb4782167e908af00a7c963373f4d2304fbe33 (diff)
2009-09-19 Ivan Maidanski <ivmai@mail.ru>
(ivmai130a.diff, ivmai130b.diff - superseding diff44, diff69) * include/gc.h (GC_do_blocking, GC_call_with_gc_active): New function prototype. * include/private/gc_priv.h (STOP_WORLD): Replace a no-op (for the single-threaded case) with an assertion check for the state to be not a "do-blocking" one. * include/private/gc_priv.h (blocking_data): Move the structure definition from pthread_support.c; change "fn" return type to void pointer. * include/private/gc_priv.h (GC_activation_frame_s): New structure type. * include/private/gc_priv.h (GC_push_all_stack_frames): New function declaration (only if THREADS). * include/private/gc_priv.h (GC_world_stopped): Don't declare unless THREADS. * include/private/gc_priv.h (GC_blocked_sp, GC_activation_frame_s): New declaration (only if not THREADS). * include/private/gc_priv.h (GC_push_all_register_frames): New function declaration (only for IA-64). * include/private/gc_priv.h (NURSERY, GC_push_proc): Remove obsolete (unused) symbols. * include/private/gc_priv.h (GC_push_all_stack_partially_eager): Remove declaration (since it is static now). * mark_rts.c (GC_push_all_stack_partially_eager): Move from mark.c (for code locality) and make STATIC. * mark_rts.c (GC_push_all_register_frames): New function (only for IA-64). * mark_rts.c (GC_push_all_stack_frames): New function (only if THREADS). * mark_rts.c (GC_add_trace_entry): New function prototype (used by GC_push_all_stack_partially_eager(), only if TRACE_BUF). * mark_rts.c (GC_push_all_stack_part_eager_frames): New function. * mar_rts.c (GC_save_regs_ret_val): Move the declaration out of a function body (only for IA-64). * mark_rts.c (GC_push_current_stack): Call GC_push_all_stack_part_eager_frames() instead of GC_push_all_stack_partially_eager(). * mark_rts.c (GC_push_current_stack): Call GC_push_all_register_frames() instead of GC_push_all_eager() for IA-64 backing store. * misc.c (GC_do_blocking_inner): Declare function (if THREADS only). * misc.c (GC_blocked_sp, GC_blocked_register_sp, GC_activation_frame): New global variables (only if not THREADS). * misc.c (GC_call_with_gc_active, GC_do_blocking_inner): New API function (only if not THREADS). * misc.c (GC_do_blocking): Move the function from pthread_support.c. * include/private/pthread_support.h (GC_Thread_Rep): Add "activation_frame" field. * pthread_stop_world.c (GC_push_all_stacks): Call GC_push_all_stack_frames() and GC_push_all_register_frames instead of GC_push_all_stack() and/or GC_push_all_eager(); don't check for STACK_GROWS_UP here. * pthread_support.c (GC_do_blocking_inner): Remove "static"; store "fn" result back to "client_data" field. * pthread_support.c (GC_call_with_gc_active): New API function. * win32_threads.c (GC_call_with_gc_active): Ditto. * win32_threads.c (GC_Thread_Rep): Add "thread_blocked_sp" and "activation_frame" fields. * win32_threads.c (GC_new_thread): Add assertion checking for thread_blocked_sp is NULL. * win32_threads.c (GC_do_blocking_inner): New function. * win32_threads.c (GC_stop_world): Don't suspend a thread if its thread_blocked_sp is non-NULL. * win32_threads.c (GC_push_stack_for): Use thread "activation_frame" (if non-NULL); use "thread_blocked_sp" if non-NULL (instead of calling GetThreadContext()); "UNPROTECT" the thread before modifying its last_stack_min; call GC_push_all_stack_frames() instead of GC_push_all_stack(); update the comments.
Diffstat (limited to 'mark_rts.c')
-rw-r--r--mark_rts.c173
1 files changed, 153 insertions, 20 deletions
diff --git a/mark_rts.c b/mark_rts.c
index 830110f..16cfce8 100644
--- a/mark_rts.c
+++ b/mark_rts.c
@@ -480,6 +480,143 @@ STATIC void GC_push_conditional_with_exclusions(ptr_t bottom, ptr_t top,
}
}
+#ifdef IA64
+/* Similar to GC_push_all_stack_frames() but for IA-64 registers store. */
+void GC_push_all_register_frames(ptr_t bs_lo, ptr_t bs_hi, int eager,
+ struct GC_activation_frame_s *activation_frame)
+{
+ while (activation_frame != NULL) {
+ ptr_t frame_bs_lo = activation_frame -> backing_store_end;
+ GC_ASSERT(frame_bs_lo <= bs_hi);
+ if (eager) {
+ GC_push_all_eager(frame_bs_lo, bs_hi);
+ } else {
+ GC_push_all_stack(frame_bs_lo, bs_hi);
+ }
+ bs_hi = activation_frame -> saved_backing_store_ptr;
+ activation_frame = activation_frame -> prev;
+ }
+ GC_ASSERT(bs_lo <= bs_hi);
+ if (eager) {
+ GC_push_all_eager(bs_lo, bs_hi);
+ } else {
+ GC_push_all_stack(bs_lo, bs_hi);
+ }
+}
+#endif /* IA64 */
+
+#ifdef THREADS
+
+void GC_push_all_stack_frames(ptr_t lo, ptr_t hi,
+ struct GC_activation_frame_s *activation_frame)
+{
+ while (activation_frame != NULL) {
+ GC_ASSERT(lo HOTTER_THAN (ptr_t)activation_frame);
+# ifdef STACK_GROWS_UP
+ GC_push_all_stack((ptr_t)activation_frame, lo);
+# else /* STACK_GROWS_DOWN */
+ GC_push_all_stack(lo, (ptr_t)activation_frame);
+# endif
+ lo = activation_frame -> saved_stack_ptr;
+ GC_ASSERT(lo != NULL);
+ activation_frame = activation_frame -> prev;
+ }
+ GC_ASSERT(!(hi HOTTER_THAN lo));
+# ifdef STACK_GROWS_UP
+ /* We got them backwards! */
+ GC_push_all_stack(hi, lo);
+# else /* STACK_GROWS_DOWN */
+ GC_push_all_stack(lo, hi);
+# endif
+}
+
+#else /* !THREADS */
+
+# ifdef TRACE_BUF
+ /* Defined in mark.c. */
+ void GC_add_trace_entry(char *kind, word arg1, word arg2);
+# endif
+
+ /* Similar to GC_push_all_eager, but only the */
+ /* part hotter than cold_gc_frame is scanned */
+ /* immediately. Needed to ensure that callee- */
+ /* save registers are not missed. */
+/*
+ * A version of GC_push_all that treats all interior pointers as valid
+ * and scans part of the area immediately, to make sure that saved
+ * register values are not lost.
+ * Cold_gc_frame delimits the stack section that must be scanned
+ * eagerly. A zero value indicates that no eager scanning is needed.
+ * We don't need to worry about the MANUAL_VDB case here, since this
+ * is only called in the single-threaded case. We assume that we
+ * cannot collect between an assignment and the corresponding
+ * GC_dirty() call.
+ */
+STATIC void GC_push_all_stack_partially_eager(ptr_t bottom, ptr_t top,
+ ptr_t cold_gc_frame)
+{
+ if (!NEED_FIXUP_POINTER && GC_all_interior_pointers) {
+ /* Push the hot end of the stack eagerly, so that register values */
+ /* saved inside GC frames are marked before they disappear. */
+ /* The rest of the marking can be deferred until later. */
+ if (0 == 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);
+# else /* STACK_GROWS_UP */
+ GC_push_all(bottom, cold_gc_frame + sizeof(ptr_t));
+ GC_push_all_eager(cold_gc_frame, top);
+# endif /* STACK_GROWS_UP */
+ } else {
+ GC_push_all_eager(bottom, top);
+ }
+# ifdef TRACE_BUF
+ GC_add_trace_entry("GC_push_all_stack", bottom, top);
+# endif
+}
+
+/* Similar to GC_push_all_stack_frames() but also uses cold_gc_frame. */
+STATIC void GC_push_all_stack_part_eager_frames(ptr_t lo, ptr_t hi,
+ ptr_t cold_gc_frame, struct GC_activation_frame_s *activation_frame)
+{
+ GC_ASSERT(activation_frame == NULL || cold_gc_frame == NULL ||
+ cold_gc_frame HOTTER_THAN (ptr_t)activation_frame);
+
+ while (activation_frame != NULL) {
+ GC_ASSERT(lo HOTTER_THAN (ptr_t)activation_frame);
+# ifdef STACK_GROWS_UP
+ GC_push_all_stack_partially_eager((ptr_t)activation_frame, lo,
+ cold_gc_frame);
+# else /* STACK_GROWS_DOWN */
+ GC_push_all_stack_partially_eager(lo, (ptr_t)activation_frame,
+ cold_gc_frame);
+# endif
+ lo = activation_frame -> saved_stack_ptr;
+ GC_ASSERT(lo != NULL);
+ activation_frame = activation_frame -> prev;
+ cold_gc_frame = NULL; /* Use at most once. */
+ }
+
+ GC_ASSERT(!(hi HOTTER_THAN lo));
+# ifdef STACK_GROWS_UP
+ /* We got them backwards! */
+ GC_push_all_stack_partially_eager(hi, lo, cold_gc_frame);
+# else /* STACK_GROWS_DOWN */
+ GC_push_all_stack_partially_eager(lo, hi, cold_gc_frame);
+# endif
+}
+
+# ifdef IA64
+ extern word GC_save_regs_ret_val;
+ /* Previously set to backing store pointer. */
+# endif
+
+#endif /* !THREADS */
+
/* Push enough of the current stack eagerly to */
/* ensure that callee-save registers saved in */
/* GC frames are scanned. */
@@ -509,38 +646,34 @@ STATIC void GC_push_current_stack(ptr_t cold_gc_frame, void * context)
GC_push_all_eager( cold_gc_frame, GC_approx_sp() );
# endif
# else
-# ifdef STACK_GROWS_DOWN
- GC_push_all_stack_partially_eager( GC_approx_sp(), GC_stackbottom,
- cold_gc_frame );
-# ifdef IA64
+ GC_push_all_stack_part_eager_frames(GC_approx_sp(), GC_stackbottom,
+ cold_gc_frame, GC_activation_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);
- }
+ ptr_t cold_gc_bs_pointer = bsp - 2048;
+ if (GC_all_interior_pointers &&
+ cold_gc_bs_pointer > BACKING_STORE_BASE) {
+ /* Adjust cold_gc_bs_pointer if below our innermost */
+ /* "activation frame" in backing store. */
+ if (GC_activation_frame != NULL && cold_gc_bs_pointer <
+ GC_activation_frame->backing_store_end)
+ cold_gc_bs_pointer = GC_activation_frame->backing_store_end;
+ GC_push_all_register_frames(BACKING_STORE_BASE,
+ cold_gc_bs_pointer, FALSE, GC_activation_frame);
+ GC_push_all_eager(cold_gc_bs_pointer, bsp);
} else {
- cold_gc_bs_pointer = BACKING_STORE_BASE;
+ GC_push_all_register_frames(BACKING_STORE_BASE, bsp,
+ TRUE /* eager */, GC_activation_frame);
}
- 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
- GC_push_all_stack_partially_eager( GC_stackbottom, GC_approx_sp(),
- cold_gc_frame );
# endif
# endif /* !THREADS */
}