summaryrefslogtreecommitdiff
path: root/src/gc
diff options
context:
space:
mode:
authorKoundinya Veluri <kouvel@users.noreply.github.com>2016-05-08 11:45:14 -0700
committerKoundinya Veluri <kouvel@users.noreply.github.com>2016-05-08 11:45:14 -0700
commit74798b5b95aca1b27050038202034448a523c9f9 (patch)
treed1c195435be53300a9c1577bb023e1fdeee2d646 /src/gc
parent70cfa355947ed82f7de8a56cac3bd38571cebfa5 (diff)
parent52e149e3bac644087463f418a0516f02a6be0060 (diff)
downloadcoreclr-74798b5b95aca1b27050038202034448a523c9f9.tar.gz
coreclr-74798b5b95aca1b27050038202034448a523c9f9.tar.bz2
coreclr-74798b5b95aca1b27050038202034448a523c9f9.zip
Merge pull request #4773 from kouvel/CardTableGrowFix3
Fix recently introduced timing issue when growing the card table
Diffstat (limited to 'src/gc')
-rw-r--r--src/gc/gc.cpp109
-rw-r--r--src/gc/gcpriv.h1
2 files changed, 64 insertions, 46 deletions
diff --git a/src/gc/gc.cpp b/src/gc/gc.cpp
index c0f60248c6..62ebc16b57 100644
--- a/src/gc/gc.cpp
+++ b/src/gc/gc.cpp
@@ -7058,9 +7058,11 @@ int gc_heap::grow_brick_card_tables (uint8_t* start,
(size_t)saved_g_lowest_address,
(size_t)saved_g_highest_address));
+ bool write_barrier_updated = false;
uint32_t virtual_reserve_flags = VirtualReserveFlags::None;
uint32_t* saved_g_card_table = g_card_table;
uint32_t* ct = 0;
+ uint32_t* translated_ct = 0;
short* bt = 0;
size_t cs = size_card_of (saved_g_lowest_address, saved_g_highest_address);
@@ -7180,10 +7182,10 @@ int gc_heap::grow_brick_card_tables (uint8_t* start,
card_table_mark_array (ct) = NULL;
#endif //MARK_ARRAY
- g_card_table = translate_card_table (ct);
+ translated_ct = translate_card_table (ct);
dprintf (GC_TABLE_LOG, ("card table: %Ix(translated: %Ix), seg map: %Ix, mark array: %Ix",
- (size_t)ct, (size_t)g_card_table, (size_t)seg_mapping_table, (size_t)card_table_mark_array (ct)));
+ (size_t)ct, (size_t)translated_ct, (size_t)seg_mapping_table, (size_t)card_table_mark_array (ct)));
#ifdef BACKGROUND_GC
if (hp->should_commit_mark_array())
@@ -7200,7 +7202,7 @@ int gc_heap::grow_brick_card_tables (uint8_t* start,
goto fail;
}
- if (!commit_mark_array_new_seg (hp, new_seg, saved_g_lowest_address))
+ if (!commit_mark_array_new_seg (hp, new_seg, translated_ct, saved_g_lowest_address))
{
dprintf (GC_TABLE_LOG, ("failed to commit mark array for the new seg"));
set_fgm_result (fgm_commit_table, logging_ma_commit_size, loh_p);
@@ -7213,51 +7215,50 @@ int gc_heap::grow_brick_card_tables (uint8_t* start,
}
#endif //BACKGROUND_GC
- {
- bool write_barrier_updated = false;
#ifdef FEATURE_USE_SOFTWARE_WRITE_WATCH_FOR_GC_HEAP
- if (gc_can_use_concurrent)
- {
- // The current design of software write watch requires that the runtime is suspended during resize. Suspending
- // on resize is preferred because it is a far less frequent operation than GetWriteWatch() / ResetWriteWatch().
- // Suspending here allows copying dirty state from the old table into the new table, and not have to merge old
- // table info lazily as done for card tables.
+ if (gc_can_use_concurrent)
+ {
+ // The current design of software write watch requires that the runtime is suspended during resize. Suspending
+ // on resize is preferred because it is a far less frequent operation than GetWriteWatch() / ResetWriteWatch().
+ // Suspending here allows copying dirty state from the old table into the new table, and not have to merge old
+ // table info lazily as done for card tables.
- BOOL is_runtime_suspended = IsSuspendEEThread();
- if (!is_runtime_suspended)
- {
- suspend_EE();
- }
+ BOOL is_runtime_suspended = IsSuspendEEThread();
+ if (!is_runtime_suspended)
+ {
+ // Note on points where the runtime is suspended anywhere in this function. Upon an attempt to suspend the
+ // runtime, a different thread may suspend first, causing this thread to block at the point of the suspend call.
+ // So, at any suspend point, externally visible state needs to be consistent, as code that depends on that state
+ // may run while this thread is blocked. This includes updates to g_card_table, g_lowest_address, and
+ // g_highest_address.
+ suspend_EE();
+ }
- SoftwareWriteWatch::SetResizedUntranslatedTable(
- mem + sw_ww_table_offset,
- saved_g_lowest_address,
- saved_g_highest_address);
+ g_card_table = translated_ct;
- // Since the runtime is already suspended, update the write barrier here as well.
- // This passes a bool telling whether we need to switch to the post
- // grow version of the write barrier. This test tells us if the new
- // segment was allocated at a lower address than the old, requiring
- // that we start doing an upper bounds check in the write barrier.
- StompWriteBarrierResize(true, la != saved_g_lowest_address);
- write_barrier_updated = true;
+ SoftwareWriteWatch::SetResizedUntranslatedTable(
+ mem + sw_ww_table_offset,
+ saved_g_lowest_address,
+ saved_g_highest_address);
- if (!is_runtime_suspended)
- {
- restart_EE();
- }
- }
-#endif // FEATURE_USE_SOFTWARE_WRITE_WATCH_FOR_GC_HEAP
+ // Since the runtime is already suspended, update the write barrier here as well.
+ // This passes a bool telling whether we need to switch to the post
+ // grow version of the write barrier. This test tells us if the new
+ // segment was allocated at a lower address than the old, requiring
+ // that we start doing an upper bounds check in the write barrier.
+ StompWriteBarrierResize(true, la != saved_g_lowest_address);
+ write_barrier_updated = true;
- if (!write_barrier_updated)
+ if (!is_runtime_suspended)
{
- // This passes a bool telling whether we need to switch to the post
- // grow version of the write barrier. This test tells us if the new
- // segment was allocated at a lower address than the old, requiring
- // that we start doing an upper bounds check in the write barrier.
- StompWriteBarrierResize(!!IsSuspendEEThread(), la != saved_g_lowest_address);
+ restart_EE();
}
}
+ else
+#endif // FEATURE_USE_SOFTWARE_WRITE_WATCH_FOR_GC_HEAP
+ {
+ g_card_table = translated_ct;
+ }
// We need to make sure that other threads executing checked write barriers
// will see the g_card_table update before g_lowest/highest_address updates.
@@ -7270,6 +7271,19 @@ int gc_heap::grow_brick_card_tables (uint8_t* start,
g_lowest_address = saved_g_lowest_address;
VolatileStore(&g_highest_address, saved_g_highest_address);
+ if (!write_barrier_updated)
+ {
+ // This passes a bool telling whether we need to switch to the post
+ // grow version of the write barrier. This test tells us if the new
+ // segment was allocated at a lower address than the old, requiring
+ // that we start doing an upper bounds check in the write barrier.
+ // This will also suspend the runtime if the write barrier type needs
+ // to be changed, so we are doing this after all global state has
+ // been updated. See the comment above suspend_EE() above for more
+ // info.
+ StompWriteBarrierResize(!!IsSuspendEEThread(), la != saved_g_lowest_address);
+ }
+
return 0;
fail:
@@ -7277,10 +7291,7 @@ fail:
if (mem)
{
- if (g_card_table != saved_g_card_table)
- {
- g_card_table = saved_g_card_table;
- }
+ assert(g_card_table == saved_g_card_table);
//delete (uint32_t*)((uint8_t*)ct - sizeof(card_table_info));
if (!GCToOSInterface::VirtualRelease (mem, alloc_size_aligned))
@@ -25260,6 +25271,7 @@ void gc_heap::verify_mark_array_cleared (heap_segment* seg, uint32_t* mark_array
BOOL gc_heap::commit_mark_array_new_seg (gc_heap* hp,
heap_segment* seg,
+ uint32_t* new_card_table,
uint8_t* new_lowest_address)
{
UNREFERENCED_PARAMETER(hp); // compiler bug? -- this *is*, indeed, referenced
@@ -25298,18 +25310,23 @@ BOOL gc_heap::commit_mark_array_new_seg (gc_heap* hp,
return FALSE;
}
- if (hp->card_table != g_card_table)
+ if (new_card_table == 0)
+ {
+ new_card_table = g_card_table;
+ }
+
+ if (hp->card_table != new_card_table)
{
if (new_lowest_address == 0)
{
new_lowest_address = g_lowest_address;
}
- uint32_t* ct = &g_card_table[card_word (gcard_of (new_lowest_address))];
+ uint32_t* ct = &new_card_table[card_word (gcard_of (new_lowest_address))];
uint32_t* ma = (uint32_t*)((uint8_t*)card_table_mark_array (ct) - size_mark_array_of (0, new_lowest_address));
dprintf (GC_TABLE_LOG, ("table realloc-ed: %Ix->%Ix, MA: %Ix->%Ix",
- hp->card_table, g_card_table,
+ hp->card_table, new_card_table,
hp->mark_array, ma));
if (!commit_mark_array_by_range (commit_start, commit_end, ma))
diff --git a/src/gc/gcpriv.h b/src/gc/gcpriv.h
index 64f37c5d35..e14cab4c62 100644
--- a/src/gc/gcpriv.h
+++ b/src/gc/gcpriv.h
@@ -2652,6 +2652,7 @@ protected:
PER_HEAP_ISOLATED
BOOL commit_mark_array_new_seg (gc_heap* hp,
heap_segment* seg,
+ uint32_t* new_card_table = 0,
uint8_t* new_lowest_address = 0);
PER_HEAP_ISOLATED