diff options
author | Ivan Maidanski <ivmai@mail.ru> | 2018-05-08 20:17:48 +0300 |
---|---|---|
committer | Ivan Maidanski <ivmai@mail.ru> | 2018-05-08 20:17:48 +0300 |
commit | e849b45c86b96b0e9f75d01a5410413f05a95822 (patch) | |
tree | 255adbc04c47e5718c774806cbdb7f84349f337f | |
parent | 404b6f264994f0b136a4eba3cb5d5060605a226e (diff) |
Fix assertion violation and partial overlapping in remove_roots_subregion
(fix of commit 38d194a)
Issue #218 (bdwgc).
* mark_rts.c [USE_PROC_FOR_LIBRARIES] (GC_remove_roots_subregion):
Update comment; add assertion that b and e pointers are word-aligned;
handle also cases of partial overlapping with the existing roots;
call GC_rebuild_root_index() only when needed; update existing root
instead of removing old and adding new one (where possible); move
newly static added root to precede dynamic ones (if any); process all
static roots even if an intersection is already found.
-rw-r--r-- | mark_rts.c | 60 |
1 files changed, 48 insertions, 12 deletions
@@ -379,15 +379,16 @@ STATIC void GC_remove_tmp_roots(void) #endif /* !defined(MSWIN32) && !defined(MSWINCE) && !defined(CYGWIN32) */ #ifdef USE_PROC_FOR_LIBRARIES - /* If there is a static root containing [b,e) then replace this root */ - /* [r_start,r_end) with roots [r_start,b) and [e,r_end). */ - /* It is assumed that GC_remove_tmp_roots() is called before this */ - /* function is called repeatedly by GC_register_map_entries(). */ + /* Remove given range from every static root which intersects with */ + /* the range. It is assumed GC_remove_tmp_roots is called before */ + /* this function is called repeatedly by GC_register_map_entries. */ GC_INNER void GC_remove_roots_subregion(ptr_t b, ptr_t e) { int i; + GC_bool rebuild = FALSE; GC_ASSERT(I_HOLD_LOCK()); + GC_ASSERT((word)b % sizeof(word) == 0 && (word)e % sizeof(word) == 0); for (i = 0; i < n_root_sets; i++) { ptr_t r_start, r_end; @@ -403,21 +404,56 @@ STATIC void GC_remove_tmp_roots(void) } r_start = GC_static_roots[i].r_start; r_end = GC_static_roots[i].r_end; - if (EXPECT((word)r_start <= (word)b && (word)e <= (word)r_end, FALSE)) { + if (!EXPECT((word)e <= (word)r_start || (word)r_end <= (word)b, TRUE)) { # ifdef DEBUG_ADD_DEL_ROOTS GC_log_printf("Removing %p .. %p from root section %d (%p .. %p)\n", (void *)b, (void *)e, i, (void *)r_start, (void *)r_end); # endif - GC_remove_root_at_pos(i); - GC_rebuild_root_index(); - if ((word)r_start < (word)b) - GC_add_roots_inner(r_start, b, FALSE); - if ((word)e < (word)r_end) - GC_add_roots_inner(e, r_end, FALSE); - break; + if ((word)r_start < (word)b) { + GC_root_size -= r_end - b; + GC_static_roots[i].r_end = b; + /* No need to rebuild as hash does not use r_end value. */ + if ((word)e < (word)r_end) { + int j; + + if (rebuild) { + GC_rebuild_root_index(); + rebuild = FALSE; + } + GC_add_roots_inner(e, r_end, FALSE); /* updates n_root_sets */ + for (j = i + 1; j < n_root_sets; j++) + if (GC_static_roots[j].r_tmp) + break; + if (j < n_root_sets-1 && !GC_static_roots[n_root_sets-1].r_tmp) { + /* Exchange the roots to have all temporary ones at the end. */ + ptr_t tmp_r_start = GC_static_roots[j].r_start; + ptr_t tmp_r_end = GC_static_roots[j].r_end; + + GC_static_roots[j].r_start = + GC_static_roots[n_root_sets-1].r_start; + GC_static_roots[j].r_end = GC_static_roots[n_root_sets-1].r_end; + GC_static_roots[j].r_tmp = FALSE; + GC_static_roots[n_root_sets-1].r_start = tmp_r_start; + GC_static_roots[n_root_sets-1].r_end = tmp_r_end; + GC_static_roots[n_root_sets-1].r_tmp = TRUE; + rebuild = TRUE; + } + } + } else { + if ((word)e < (word)r_end) { + GC_root_size -= e - r_start; + GC_static_roots[i].r_start = e; + } else { + GC_remove_root_at_pos(i); + i--; + } + rebuild = TRUE; + } } } + if (rebuild) + GC_rebuild_root_index(); } #endif /* USE_PROC_FOR_LIBRARIES */ |